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

Added possibility to create a GenericOp from any Operator

parent e7869ad3
No related branches found
No related tags found
2 merge requests!318[Upd] release verision 0.5.0,!272[Add] Possibility to create a GenericOperator from any Operator
Pipeline #60640 passed
......@@ -75,6 +75,10 @@ public:
inline void addAttr(const std::string& name, const T& value) const
{ mAttributes -> template addAttr<T>(name, value); }
inline void setAttrs(const std::map<std::string, future_std::any>& attrs) {
*mAttributes = attrs;
}
// Helper functions that can be used with setForwardDims():
static const ComputeDimsFunc Identity;
static const ComputeDimsFunc InputIdentity(IOIndex_t inputIdx, IOIndex_t nbOutputs);
......@@ -84,9 +88,9 @@ public:
};
/**
* @brief Fictive custom operator not associated with any implementation.
* @brief Generic operator not associated with any implementation.
* Allows to import unknown operators and simulate new ones.
* @param type Type of the fictive operator.
* @param type Type of the generic operator.
* @param inputCategory List inputs with their category
* @param nbOut Number of output data.
* @param name (optional) name of the Operator.
......@@ -96,9 +100,9 @@ std::shared_ptr<Node> GenericOperator(const std::string& type, const std::vector
const std::string& name = "");
/**
* @brief Fictive custom operator not associated with any implementation.
* @brief Generic operator not associated with any implementation.
* Allows to import unknown operators and simulate new ones.
* @param type Type of the fictive operator.
* @param type Type of the generic operator.
* @param nbData Number of input data.
* @param nbParam Number of parameters.
* @param nbOut Number of output data.
......@@ -107,6 +111,18 @@ std::shared_ptr<Node> GenericOperator(const std::string& type, const std::vector
*/
std::shared_ptr<Node> GenericOperator(const std::string& type, IOIndex_t nbData, IOIndex_t nbParam, IOIndex_t nbOut,
const std::string& name = "");
/**
* @brief Generic operator not associated with any implementation.
* Create a generic operator from another existing operator.
* @param type Type of the generic operator.
* @param op Original operator from witch one wants to derive a generic operator.
* @param name (optional) name of the Operator.
* @return std::shared_ptr<Node> Node associated with the Generic Operator.
*/
std::shared_ptr<Aidge::Node> GenericOperator(const std::string& type,
std::shared_ptr<OperatorTensor> op,
const std::string& name = "");
} // namespace Aidge
#endif /* AIDGE_CORE_OPERATOR_GENERICOPERATOR_H_ */
......@@ -196,6 +196,10 @@ public:
return mOperatorType;
}
inline std::vector<InputCategory> inputCategory() const {
return mInputsCategory;
}
inline InputCategory inputCategory(IOIndex_t idx) const {
// AIDGE_ASSERT(idx < mInputsCategory.size(), "Input #{} out of range (number of inputs is {})", idx, mInputsCategory.size());
return mInputsCategory.at(idx);
......
......@@ -41,6 +41,10 @@ class DynamicAttributes : public Attributes {
public:
DynamicAttributes() = default;
DynamicAttributes(const std::map<std::string, future_std::any>& attrs): mAttrs(attrs) {}
DynamicAttributes& operator=(const std::map<std::string, future_std::any>& attrs) {
mAttrs = attrs;
return *this;
}
/**
* \brief Returning an Attribute identified by its name
......
......@@ -39,6 +39,30 @@ void init_GenericOperator(py::module& m) {
.def("set_forward_dims", &GenericOperator_Op::setForwardDims, py::arg("computation_function"));
// &GenericOperator
m.def("GenericOperator",
[]( const std::string& type,
const std::vector<Aidge::InputCategory>& inputCategory,
IOIndex_t nbOut,
const std::string& name,
const py::kwargs kwargs){
std::shared_ptr<Node> genericNode = GenericOperator(
type,
inputCategory,
nbOut,
name
);
if (kwargs){
std::shared_ptr<GenericOperator_Op> gop = std::static_pointer_cast<GenericOperator_Op>(genericNode->getOperator());
std::shared_ptr<DynamicAttributes> attr = std::dynamic_pointer_cast<DynamicAttributes>(gop->attributes());
for (auto item : kwargs) {
std::string key = py::cast<std::string>(item.first);
py::object value = py::reinterpret_borrow<py::object>(item.second);
attr->setAttrPy(key, std::move(value));
}
}
return genericNode;
}, py::arg("type"), py::arg("input_category"), py::arg("nb_out"), py::arg("name") = "");
m.def("GenericOperator",
[]( const std::string& type,
IOIndex_t nbData,
......@@ -65,6 +89,8 @@ void init_GenericOperator(py::module& m) {
return genericNode;
}, py::arg("type"), py::arg("nb_data"), py::arg("nb_param"), py::arg("nb_out"), py::arg("name") = "");
m.def("GenericOperator", py::overload_cast<const std::string&, std::shared_ptr<OperatorTensor>, const std::string&>(&GenericOperator), py::arg("type"), py::arg("op"), py::arg("name") = "");
declare_registrable<GenericOperator_Op>(m, "GenericOperatorOp");
}
} // namespace Aidge
......@@ -44,7 +44,14 @@ void init_Operator(py::module& m){
.def("get_raw_input", &Operator::getRawInput, py::arg("inputIdx"))
.def("nb_inputs", &Operator::nbInputs)
.def("nb_outputs", &Operator::nbOutputs)
.def("input_category", &Operator::inputCategory, py::arg("idx"),
.def("input_category", static_cast<std::vector<InputCategory>(Operator::*)() const>(&Operator::inputCategory),
R"mydelimiter(
Category of the inputs (Data or Param, optional or not).
Data inputs exclude inputs expecting parameters (weights or bias).
:rtype: list(InputCategory)
)mydelimiter")
.def("input_category", static_cast<InputCategory(Operator::*)(IOIndex_t) const>(&Operator::inputCategory), py::arg("idx"),
R"mydelimiter(
Category of a specific input (Data or Param, optional or not).
Data inputs exclude inputs expecting parameters (weights or bias).
......
......@@ -73,7 +73,8 @@ bool Aidge::GenericOperator_Op::forwardDims(bool /*allowDataDependency*/) {
}
const auto& outputsDims = mForwardDims(inputsDims);
AIDGE_ASSERT((outputsDims.size() == nbOutputs()), "The provided ComputeDimsFunc function returns the wrong number of outputs");
AIDGE_ASSERT(!outputsDims.empty(), "The provided ComputeDimsFunc cannot compute the output dims (an empty vector was returned)");
AIDGE_ASSERT(outputsDims.size() == nbOutputs(), "The provided ComputeDimsFunc function returned the wrong number of outputs: {}, but {} are expected", outputsDims.size(), nbOutputs());
for (std::size_t i = 0; i < nbOutputs(); ++i) {
mOutputs[i]->resize(outputsDims[i]);
}
......@@ -117,3 +118,40 @@ std::shared_ptr<Aidge::Node> Aidge::GenericOperator(const std::string& type,
const std::string& name) {
return std::make_shared<Node>(std::make_shared<GenericOperator_Op>(type, nbData, nbParam, nbOut), name);
}
std::shared_ptr<Aidge::Node> Aidge::GenericOperator(const std::string& type,
std::shared_ptr<OperatorTensor> op,
const std::string& name)
{
// Create a generic op with the same inputs/outputs
auto genericOp = std::make_shared<GenericOperator_Op>(type, op->inputCategory(), op->nbOutputs());
// Copy attributes
genericOp->setAttrs(op->attributes()->getAttrs());
// Set a default forward dims if possible
if (op->dimsForwarded()) {
auto opInputDims = std::vector<std::vector<DimSize_t>>(op->nbInputs());
for (size_t i = 0; i < op->nbInputs(); ++i) {
opInputDims[i] = op->getInput(i)->dims();
}
auto opOutputDims = std::vector<std::vector<DimSize_t>>(op->nbOutputs());
for (size_t o = 0; o < op->nbOutputs(); ++o) {
opOutputDims[o] = op->getOutput(o)->dims();
}
genericOp->setForwardDims([opInputDims, opOutputDims](const std::vector<std::vector<std::size_t>>& inputsDims) {
// Check input dims
for (size_t i = 0; i < opInputDims.size(); ++i) {
if (inputsDims[i] != opInputDims[i]) {
// No matching => unable to compute output dims!
return std::vector<std::vector<std::size_t>>();
}
}
return opOutputDims;
});
}
return std::make_shared<Node>(genericOp, name);
}
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