Skip to content
Snippets Groups Projects
Commit 5052290b authored by Houssem ROUIS's avatar Houssem ROUIS
Browse files

Merge branch aidge_core:main into vit_operators

parents e244efba 3182ea4a
No related branches found
No related tags found
2 merge requests!59Improvements and fixes,!47Vit operators
......@@ -83,4 +83,4 @@ class Connector {
std::shared_ptr<GraphView> generateGraph(std::vector<Connector> ctors);
} // namespace Aidge
#endif /* AIDGE_CORE_GRAPH_CONNECTOR_H_ */
\ No newline at end of file
#endif /* AIDGE_CORE_GRAPH_CONNECTOR_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
*
********************************************************************************/
#ifndef AIDGE_CORE_OPERATOR_IDENTITY_H_
#define AIDGE_CORE_OPERATOR_IDENTITY_H_
#include <cassert>
#include <memory>
#include <vector>
#include "aidge/utils/Registrar.hpp"
#include "aidge/operator/Operator.hpp"
#include "aidge/backend/OperatorImpl.hpp"
#include "aidge/data/Tensor.hpp"
#include "aidge/data/Data.hpp"
#include "aidge/graph/Node.hpp"
#include "aidge/utils/Types.h"
namespace Aidge {
/**
* @brief Indentity_Op is an helper operator made to ease the declaration of MetaNodes.
* This Operator has no Implementation, it just forward its input Tensor.
* Note: Error may occur if new methods are added in Operator which use an implementation.
* Has we need to update this class to remove the use of Impl.
*
*/
class Identity_Op : public Operator,
public Registrable<Identity_Op, std::string, std::unique_ptr<OperatorImpl>(const Identity_Op&)> {
public:
// FIXME: change accessibility
std::shared_ptr<Tensor> mInput = std::make_shared<Tensor>();
public:
static constexpr const char* Type = "Identity";
Identity_Op()
: Operator(Type)
{
setDatatype(DataType::Float32);
mImpl = std::make_shared<OperatorImpl>(*this);
}
/**
* @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.
*/
Identity_Op(const Identity_Op& op)
: Operator(Type)
{
// cpy-ctor
setDatatype(op.mInput->dataType());
mImpl = std::make_shared<OperatorImpl>(*this);
}
/**
* @brief Clone the operator using its copy-constructor.
* @see Operator::Identity_Op
*/
std::shared_ptr<Operator> clone() const override {
return std::make_shared<Identity_Op>(*this);
}
void associateInput(const IOIndex_t inputIdx, std::shared_ptr<Data> data) override final {
assert(inputIdx == 0 && "operator supports only 1 input");
(void) inputIdx; // avoid unused warning
assert(strcmp(data->type(), Tensor::Type)==0 && "input data must be of Tensor type");
mInput = std::dynamic_pointer_cast<Tensor>(data);
}
void computeOutputDims() override final {} // Do nothing
bool outputDimsForwarded() const override final {
return true;
}
void forward() override { runHooks(); }
void backward() override { }
inline Tensor& input(const IOIndex_t /*inputIdx*/) const override final { return *(mInput.get()); }
// output = input
inline Tensor& output(const IOIndex_t /*outputIdx*/) const override final { return *(mInput.get()); }
inline std::shared_ptr<Tensor> getInput(const IOIndex_t inputIdx) const override final {
assert((inputIdx == 0) && "ReLU Operator has only 1 input");
(void) inputIdx; // avoid unused warning
return mInput;
}
inline std::shared_ptr<Tensor> getOutput(const IOIndex_t outputIdx) const override final {
assert((outputIdx == 0) && "Identity Operator has only 1 output");
(void) outputIdx; // avoid unused warning
return mInput;
}
std::shared_ptr<Data> getRawInput(const IOIndex_t inputIdx) const override final {
assert(inputIdx == 0 && "operator supports only 1 input");
(void) inputIdx; // avoid unused warning
return std::static_pointer_cast<Data>(mInput);
}
std::shared_ptr<Data> getRawOutput(const IOIndex_t outputIdx) const override final {
assert(outputIdx == 0 && "operator supports only 1 output");
(void) outputIdx; // avoid unused warning
return std::static_pointer_cast<Data>(mInput);
}
void setBackend(const std::string& name) override {
// setBackend do nothing, Identity node has no backend it just pass the same Tensor
}
void setDatatype(const DataType& datatype) override {
// setDatatype do nothing, Identity node has no backend it just pass the same Tensor
}
inline IOIndex_t nbInputs() const noexcept override final { return 1; }
inline IOIndex_t nbDataInputs() const noexcept override final { return 1; }
inline IOIndex_t nbOutputs() const noexcept override final { return 1; }
static const std::vector<std::string> getInputsName(){
return {"data_input"};
}
static const std::vector<std::string> getOutputsName(){
return {"data_output"};
}
};
inline std::shared_ptr<Node> Identity(const std::string& name = "") {
return std::make_shared<Node>(std::make_shared<Identity_Op>(), name);
}
}
#endif /* AIDGE_CORE_OPERATOR_IDENTITY_H_ */
......@@ -51,9 +51,18 @@ void init_GraphView(py::module& m) {
Include a Node to the current GraphView object.
:param other_node: Node to add
:type oth_Node: Node
:param includeLearnableParameter: include non-data inputs, like weights and biases. Default True.
:type includeLearnableParameter: bool
:type other_node: Node
:param include_learnable_parameters: include non-data inputs, like weights and biases, default True.
:type include_learnable_parameters: bool, optional
)mydelimiter")
.def("add", (void (GraphView::*)(std::shared_ptr<GraphView>)) & GraphView::add,
py::arg("other_graph"),
R"mydelimiter(
Include a GraphView to the current GraphView object.
:param other_graph: GraphView to add
:type other_graph: GraphView
)mydelimiter")
.def("add_child",
......@@ -105,4 +114,4 @@ void init_GraphView(py::module& m) {
// })
;
}
} // namespace Aidge
\ No newline at end of file
} // namespace Aidge
......@@ -16,136 +16,150 @@
#include "aidge/graph/GraphView.hpp"
#include "aidge/graph/Node.hpp"
#include "aidge/graph/Connector.hpp"
#include "aidge/utils/Types.h"
namespace py = pybind11;
namespace Aidge {
void init_Node(py::module& m) {
py::class_<Node, std::shared_ptr<Node>>(m, "Node")
.def("name", &Node::name,
R"mydelimiter(
Name of the Node.
)mydelimiter")
.def("type", &Node::type,
R"mydelimiter(
Type of the node.
)mydelimiter")
.def("get_operator", &Node::getOperator,
R"mydelimiter(
Get the Operator object of the Node.
)mydelimiter")
.def("set_name", &Node::setName, py::arg("name"),
R"mydelimiter(
Set the Node name.
:param name: New name for the node.
:type name: str
:rtype: str
)mydelimiter")
.def("add_child",
(void (Node::*)(std::shared_ptr<Node>, const IOIndex_t, IOIndex_t)) &
Node::addChild,
py::arg("other_node"), py::arg("out_id") = 0, py::arg("other_in_id") = gk_IODefaultIndex,
R"mydelimiter(
Link another Node to an output of the current Node.
:param other_node: Pointer to the other Node.
:type other_node: :py:class: Node
:param out_id: ID of the current Node output to connect to the other Node. Default to 0.
:type out_id: int
:param other_in_id: ID of the other Node input to connect to the current Node. Default to the first avaible data input.
:type other_in_id: int
)mydelimiter")
.def("add_child",
(void (Node::*)(std::shared_ptr<GraphView>, const IOIndex_t,
std::pair<std::shared_ptr<Node>, IOIndex_t>)) &
Node::addChild,
py::arg("other_graph"), py::arg("out_id") = 0,
py::arg("other_in_id") =
std::pair<std::shared_ptr<Node>, IOIndex_t>(nullptr, gk_IODefaultIndex),
R"mydelimiter(
Link a Node from a specific GraphView to the current Node.
:param other_view: Pointer to the GraphView whose content should be linked to the current Node.
:type other_view: :py:class: GraphView
:param out_id: ID of the current Node output to connect to the other Node. Default to 0.
:type out_id: int
:param other_in_id: Pair of Node and input connection ID for specifying the connection. If the GraphView whose content is linked has only one input Node, then it defaults to the first available data input ID of this Node.
:type other_in_id: tuple[:py:class: Node, int]
)mydelimiter")
.def("inputs", &Node::inputs,
R"mydelimiter(
Get ordered list of parent Node and the associated output index connected to the current Node's inputs.
:return: List of connections. When an input is not linked to any parent, the default value is (None, default_index)
:rtype: list[tuple[Node, int]]
)mydelimiter")
.def("input", &Node::input, py::arg("in_id"),
R"mydelimiter(
Get the parent Node and the associated output index connected to the i-th input of the current Node.
:param in_id: input index of the current Node object.
:type in_id: int
:return: i-th connection. When an input is not linked to any parent, the default value is (None, default_index)
:rtype: tuple[Node, int]
)mydelimiter")
.def("outputs", &Node::outputs,
R"mydelimiter(
Get, for each output of the Node, a list of the children Node and the associated input index connected to it.
:return: List of a list of connections. When an outut is not linked to any child, its list a empty.
:rtype: list[list[tuple[Node, int]]]
)mydelimiter")
.def("output", &Node::output, py::arg("out_id"),
R"mydelimiter(
Get a list of the children Node for a specific output and the associated input index connected to it.
:param out_id: input index of the current Node object.
:type out_id: int
:return: i-th connection. When an input is not linked to any parent, the default value is (None, default_index)
:rtype: list[tuple[Node, int]]
)mydelimiter")
.def("get_nb_inputs", &Node::nbInputs,
R"mydelimiter(
Number of inputs.
:rtype: int
)mydelimiter")
.def("get_nb_datainputs", &Node::nbDataInputs,
R"mydelimiter(
Number of data inputs.
:rtype: int
)mydelimiter")
.def("get_nb_outputs", &Node::nbOutputs,
R"mydelimiter(
Number of outputs.
:rtype: int
)mydelimiter")
.def("get_parents", &Node::getParents,
R"mydelimiter(
Get parents.
)mydelimiter")
.def("get_children", (std::set<std::shared_ptr<Node>> (Node::*)() const) &Node::getChildren,
R"mydelimiter(
Get children.
)mydelimiter")
.def("__call__", &Node::operator(), py::arg("connectors"));
.def("name", &Node::name,
R"mydelimiter(
Name of the Node.
)mydelimiter")
.def("type", &Node::type,
R"mydelimiter(
Type of the node.
)mydelimiter")
.def("get_operator", &Node::getOperator,
R"mydelimiter(
Get the Operator object of the Node.
)mydelimiter")
.def("set_name", &Node::setName, py::arg("name"),
R"mydelimiter(
Set the Node name.
:param name: New name for the node.
:type name: str
:rtype: str
)mydelimiter")
.def("add_child",
(void (Node::*)(std::shared_ptr<Node>, const IOIndex_t, IOIndex_t)) &
Node::addChild,
py::arg("other_node"), py::arg("out_id") = 0, py::arg("other_in_id") = gk_IODefaultIndex,
R"mydelimiter(
Link another Node to an output of the current Node.
:param other_node: Pointer to the other Node.
:type other_node: :py:class: Node
:param out_id: ID of the current Node output to connect to the other Node. Default to 0.
:type out_id: int
:param other_in_id: ID of the other Node input to connect to the current Node. Default to the first avaible data input.
:type other_in_id: int
)mydelimiter")
.def("add_child",
(void (Node::*)(std::shared_ptr<GraphView>, const IOIndex_t,
std::pair<std::shared_ptr<Node>, IOIndex_t>)) &
Node::addChild,
py::arg("other_graph"), py::arg("out_id") = 0,
py::arg("other_in_id") =
std::pair<std::shared_ptr<Node>, IOIndex_t>(nullptr, gk_IODefaultIndex),
R"mydelimiter(
Link a Node from a specific GraphView to the current Node.
:param other_view: Pointer to the GraphView whose content should be linked to the current Node.
:type other_view: :py:class: GraphView
:param out_id: ID of the current Node output to connect to the other Node. Default to 0.
:type out_id: int
:param other_in_id: Pair of Node and input connection ID for specifying the connection. If the GraphView whose content is linked has only one input Node, then it defaults to the first available data input ID of this Node.
:type other_in_id: tuple[:py:class: Node, int]
)mydelimiter")
.def("inputs", &Node::inputs,
R"mydelimiter(
Get ordered list of parent Node and the associated output index connected to the current Node's inputs.
:return: List of connections. When an input is not linked to any parent, the default value is (None, default_index)
:rtype: list[tuple[Node, int]]
)mydelimiter")
.def("input", &Node::input, py::arg("in_id"),
R"mydelimiter(
Get the parent Node and the associated output index connected to the i-th input of the current Node.
:param in_id: input index of the current Node object.
:type in_id: int
:return: i-th connection. When an input is not linked to any parent, the default value is (None, default_index)
:rtype: tuple[Node, int]
)mydelimiter")
.def("outputs", &Node::outputs,
R"mydelimiter(
Get, for each output of the Node, a list of the children Node and the associated input index connected to it.
:return: List of a list of connections. When an outut is not linked to any child, its list a empty.
:rtype: list[list[tuple[Node, int]]]
)mydelimiter")
.def("output", &Node::output, py::arg("out_id"),
R"mydelimiter(
Get a list of the children Node for a specific output and the associated input index connected to it.
:param out_id: input index of the current Node object.
:type out_id: int
:return: i-th connection. When an input is not linked to any parent, the default value is (None, default_index)
:rtype: list[tuple[Node, int]]
)mydelimiter")
.def("get_nb_inputs", &Node::nbInputs,
R"mydelimiter(
Number of inputs.
:rtype: int
)mydelimiter")
.def("get_nb_datainputs", &Node::nbDataInputs,
R"mydelimiter(
Number of data inputs.
:rtype: int
)mydelimiter")
.def("get_nb_outputs", &Node::nbOutputs,
R"mydelimiter(
Number of outputs.
:rtype: int
)mydelimiter")
.def("get_parents", &Node::getParents,
R"mydelimiter(
Get parents.
)mydelimiter")
.def("get_children", (std::set<std::shared_ptr<Node>> (Node::*)() const) &Node::getChildren,
R"mydelimiter(
Get children.
)mydelimiter")
.def("__call__",
[](Node &self, pybind11::args args) {
std::vector<Connector> connectors;
for (const auto &arg : args) {
// Check if the argument is an instance of Connector
if (pybind11::isinstance<Connector>(arg)) {
// Convert Python object to C++ object adn push it ot vector
connectors.push_back(arg.cast<Connector>());
} else {
throw std::runtime_error("One of the arguments was not a Connector.");
}
}
return self(connectors);
});
}
} // namespace Aidge
/********************************************************************************
* 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 "aidge/operator/Identity.hpp"
#include "aidge/operator/Operator.hpp"
namespace py = pybind11;
namespace Aidge {
void init_Identity(py::module& m) {
py::class_<Identity_Op, std::shared_ptr<Identity_Op>, Operator>(m, "IdentityOp", py::multiple_inheritance())
.def("get_inputs_name", &Identity_Op::getInputsName)
.def("get_outputs_name", &Identity_Op::getOutputsName);
m.def("Identity", &Identity, py::arg("name") = "");
}
} // namespace Aidge
......@@ -121,6 +121,15 @@ void init_MetaOperatorDefs(py::module &m) {
declare_PaddedMaxPoolingOp<2>(m);
declare_PaddedMaxPoolingOp<3>(m);
py::class_<MetaOperator_Op, std::shared_ptr<MetaOperator_Op>, Operator>(m, "MetaOperator_Op", py::multiple_inheritance());
m.def("meta_operator", &MetaOperator,
py::arg("type"),
py::arg("graph"),
py::arg("name") = "",
py::arg("input_nodes") = std::vector<NodePtr>(),
py::arg("output_nodes") = std::vector<NodePtr>()
);
}
} // namespace Aidge
......@@ -23,6 +23,7 @@ void init_Operator(py::module& m){
.def("nb_inputs", &Operator::nbInputs)
.def("nb_data_inputs", &Operator::nbDataInputs)
.def("nb_outputs", &Operator::nbOutputs)
.def("output_dims_forwarded", &Operator::outputDimsForwarded)
.def("associate_input", &Operator::associateInput, py::arg("inputIdx"), py::arg("data"))
.def("set_datatype", &Operator::setDatatype, py::arg("datatype"))
.def("set_backend", &Operator::setBackend, py::arg("name"))
......
......@@ -39,6 +39,7 @@ void init_ReLU(py::module&);
void init_Softmax(py::module&);
void init_Sqrt(py::module&);
void init_Sub(py::module&);
void init_Identity(py::module&);
void init_Node(py::module&);
void init_GraphView(py::module&);
......@@ -83,6 +84,7 @@ void init_Aidge(py::module& m){
init_Softmax(m);
init_Sqrt(m);
init_Sub(m);
init_Identity(m);
init_Producer(m);
init_GraphRegex(m);
......
......@@ -41,6 +41,7 @@ std::shared_ptr<Aidge::GraphView> Aidge::generateGraph(std::vector<Connector> ct
std::vector<std::shared_ptr<Node>> parents = nodesToAdd.back()->getParents();
const std::set<std::shared_ptr<Node>>& alreadyAdded = graph->getNodes();
for (std::shared_ptr<Node> parent : parents) {
if (!parent) continue;
if (alreadyAdded.find(parent) == alreadyAdded.end()) {
buffer.push_back(parent);
}
......@@ -51,4 +52,4 @@ std::shared_ptr<Aidge::GraphView> Aidge::generateGraph(std::vector<Connector> ct
buffer = {};
}
return graph;
}
\ No newline at end of file
}
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