diff --git a/include/aidge/data/Tensor.hpp b/include/aidge/data/Tensor.hpp index aab6f375765e87c8978d08fddfbcfc76f9a6990c..681e8ca618795a85a1e3a55a413dbfd74d5b0ea2 100644 --- a/include/aidge/data/Tensor.hpp +++ b/include/aidge/data/Tensor.hpp @@ -15,7 +15,7 @@ #include <cstring> #include <set> #include <memory> -#include <numeric> +#include <numeric> // std::accumulate #include <string> #include <vector> @@ -327,11 +327,11 @@ class Tensor : public Data, /** * @brief Change the dimensions of the Tensor object according to the given argument. - * If the overall size is not changed (meaning we actually only performed a + * If the overall size is not changed (meaning we actually only performed a * reshape), data is garanteed to remain valid. - * Otherwise, no garantee is provided regarding the validy of previous data - * (unlike std::vector). If the new overall size is larger than the previous - * one, all previous data is invalided. Otherwise, previous data may or may + * Otherwise, no garantee is provided regarding the validy of previous data + * (unlike std::vector). If the new overall size is larger than the previous + * one, all previous data is invalided. Otherwise, previous data may or may * not remain valid, depending on the backend implementation. * @tparam DIM Number of dimensions. * @param dims New dimensions @@ -343,11 +343,11 @@ class Tensor : public Data, /** * @brief Change the dimensions of the Tensor object according to the given argument. - * If the overall size is not changed (meaning we actually only performed a + * If the overall size is not changed (meaning we actually only performed a * reshape), data is garanteed to remain valid. - * Otherwise, no garantee is provided regarding the validy of previous data - * (unlike std::vector). If the new overall size is larger than the previous - * one, all previous data is invalided. Otherwise, previous data may or may + * Otherwise, no garantee is provided regarding the validy of previous data + * (unlike std::vector). If the new overall size is larger than the previous + * one, all previous data is invalided. Otherwise, previous data may or may * not remain valid, depending on the backend implementation. * @param dims New dimensions */ @@ -424,7 +424,7 @@ class Tensor : public Data, return std::string("?"); // To make Clang happy }; - if (dims().empty()) { return "{}"; } + if (dims().empty()) { return ptrToString(mDataType, mImpl->hostPtr(), 0); } std::string res; std::size_t dim = 0; std::size_t counter = 0; @@ -546,22 +546,22 @@ class Tensor : public Data, /** * Copy-cast data from a Tensor. * @param src Source tensor to copy-cast from. - * @param movedSrc shared_ptr to an indermediate Tensor that will - * contain the moved data if a device change should occur AND a type + * @param movedSrc shared_ptr to an indermediate Tensor that will + * contain the moved data if a device change should occur AND a type * conversion is necessary (otherwise it remains unused). - * Any data already present will be overwritten. No new memory allocation - * will occur if movedSrc has already been allocated with the right + * Any data already present will be overwritten. No new memory allocation + * will occur if movedSrc has already been allocated with the right * type/size/device. - * If required, memory is always allocated on current (destination) + * If required, memory is always allocated on current (destination) * Tensor's device. */ void copyCastFrom(const Tensor& src, std::shared_ptr<Tensor>& movedSrc); /** * Copy-cast data from a Tensor. - * In case of both a device change AND a data type conversion, an + * In case of both a device change AND a data type conversion, an * intermediate buffer on will be allocated and deallocated each time. - * If required, buffer's memory is always allocated on current (destination) + * If required, buffer's memory is always allocated on current (destination) * Tensor's device. * @param src Source tensor to copy-cast from. */ @@ -579,7 +579,7 @@ class Tensor : public Data, * The backend stays the same. * @param fallback A shared_ptr to Tensor ready to be overwritten if necessary. * The shared_ptr does not need to be initialized. No new memory allocation - * will occur if fallback has already been allocated with the right + * will occur if fallback has already been allocated with the right * type/size/device. * @param dt The desired data type. * @return Reference to either itself or to fallback. @@ -594,7 +594,7 @@ class Tensor : public Data, * The data type stays the same. * @param fallback A shared_ptr to Tensor ready to be overwritten if necessary. * The shared_ptr does not need to be initialized. No new memory allocation - * will occur if fallback has already been allocated with the right + * will occur if fallback has already been allocated with the right * type/size/device. * @param backend The desired backend. * @param device The desired device. @@ -607,11 +607,11 @@ class Tensor : public Data, * Return a reference to a Tensor on desired data type and backend/device: * - itself, if already with the right characteristics; * - the provided Tensor, overwritten with the copy-casted data. - * If required, fallback is always allocated on desired (destination) + * If required, fallback is always allocated on desired (destination) * device. * @param fallback A shared_ptr to Tensor ready to be overwritten if necessary. * The shared_ptr does not need to be initialized. No new memory allocation - * will occur if fallback has already been allocated with the right + * will occur if fallback has already been allocated with the right * type/size/device. * @param dt The desired data type. * @param backend The desired backend. @@ -628,11 +628,11 @@ class Tensor : public Data, * (data type, backend/device) as targetReqs Tensor: * - itself, if already with the right characteristics; * - the provided Tensor, overwritten with the copy-casted data. - * If required, fallback is always allocated on current (destination) + * If required, fallback is always allocated on current (destination) * Tensor's device. * @param fallback A shared_ptr to Tensor ready to be overwritten if necessary. * The shared_ptr does not need to be initialized. No new memory allocation - * will occur if fallback has already been allocated with the right + * will occur if fallback has already been allocated with the right * type/size/device. * @param targetReqs Tensor with the desired target characteristics. * @return Reference to either itself or to fallback. @@ -644,15 +644,8 @@ class Tensor : public Data, private: ///\bug not protected against overflow - std::size_t computeSize() { - if (mDims.empty()) { - mSize = DimSize_t(0); - } - else { - mSize = std::accumulate(mDims.begin(), mDims.end(), DimSize_t(1), std::multiplies<DimSize_t>()); - } - - return mSize; + void computeSize() { + mSize = std::accumulate(mDims.begin(), mDims.end(), DimSize_t(1), std::multiplies<DimSize_t>()); } }; } // namespace Aidge diff --git a/include/aidge/operator/Identity.hpp b/include/aidge/operator/Identity.hpp index 7348fa10a96c55914bae68983b5e3bd4a9c40b12..57cd20311a4e4c98966af0af98b9fe4533155ea6 100644 --- a/include/aidge/operator/Identity.hpp +++ b/include/aidge/operator/Identity.hpp @@ -40,7 +40,7 @@ public: static const std::string Type; Identity_Op() - : OperatorTensor(Type, 1, 0, 0) + : OperatorTensor(Type, 1, 0, 1) { mImpl = std::make_shared<OperatorImpl>(*this); } @@ -101,7 +101,10 @@ public: if (outputIdx >= nbInputs()) { AIDGE_THROW_OR_ABORT(std::runtime_error, "%s Operator has %hu outputs", type().c_str(), nbInputs()); } - return mInputs[outputIdx]; + if (mInputs[outputIdx] == nullptr){ + return mOutputs[outputIdx]; // Input is not initialized with empty tensor + } + return mInputs[outputIdx]; // Identity, so Output is Input } void setBackend(const std::string& /*name*/, DeviceIdx_t /*device*/ = 0) override final { // setBackend do nothing, Identity node has no backend it just pass the same Tensor diff --git a/include/aidge/operator/Producer.hpp b/include/aidge/operator/Producer.hpp index ee00ead696efe623a4e051994f470a38397777ec..fe9b044e2309eb7e724d6648b84c044d7407bafb 100644 --- a/include/aidge/operator/Producer.hpp +++ b/include/aidge/operator/Producer.hpp @@ -24,22 +24,32 @@ namespace Aidge { +enum class ProdAttr { Constant }; + class Producer_Op : public OperatorTensor, public Registrable<Producer_Op, std::string, std::unique_ptr<OperatorImpl>( - const Producer_Op &)> { + const Producer_Op &)>, + public StaticAttributes<ProdAttr, bool> { public: static const std::string Type; + using Attributes_ = StaticAttributes<ProdAttr, bool>; + template <ProdAttr e> + using attr = typename Attributes_::template attr<e>; + template <std::size_t DIM> - Producer_Op(const std::array<DimSize_t, DIM>& dims) - : OperatorTensor(Type, 0, 0, 1) + Producer_Op(const std::array<DimSize_t, DIM>& dims, + bool constant = false) + : OperatorTensor(Type, 0, 0, 1), + Attributes_(attr<ProdAttr::Constant>(constant)) { mOutputs[0]->resize(dims); } - Producer_Op(const std::shared_ptr<Tensor> tensor) - : OperatorTensor(Type, 0, 0, 1) + Producer_Op(const std::shared_ptr<Tensor> tensor, bool constant = false) + : OperatorTensor(Type, 0, 0, 1), + Attributes_(attr<ProdAttr::Constant>(constant)) { mOutputs[0] = tensor; // copy the pointer of the Tensor } @@ -49,7 +59,8 @@ public: * @param op OperatorTensor to copy. */ Producer_Op(const Producer_Op& op) - : OperatorTensor(op) + : OperatorTensor(op), + Attributes_(op) { for (std::size_t i = 0; i < static_cast<std::size_t>(nbOutputs()); ++i) { mOutputs[i] = std::make_shared<Tensor>(*(op.getOutput(i))); @@ -89,28 +100,41 @@ public: } public: - void forward() override final { - printf("Basic Producer forward() function.\n"); - } - void backward() override final { - printf("Basic Producer backward() function.\n"); - } + void forward() override final { + printf("Basic Producer forward() function.\n"); + } + void backward() override final { + printf("Basic Producer backward() function.\n"); + } + void setOutput(const Aidge::IOIndex_t outputIdx, std::shared_ptr<Aidge::Data>&& data) override { + if (getAttr<ProdAttr::Constant>()) { + AIDGE_THROW_OR_ABORT(std::runtime_error, "Producer is constant, cannot update output."); + } + OperatorTensor::setOutput(outputIdx, std::move(data)); + } + + void setOutput(const Aidge::IOIndex_t outputIdx, const std::shared_ptr<Aidge::Data>& data) override { + if (getAttr<ProdAttr::Constant>()) { + AIDGE_THROW_OR_ABORT(std::runtime_error, "Producer is constant, cannot update output."); + } + OperatorTensor::setOutput(outputIdx, data); + } }; template <std::array<DimSize_t, 1>::size_type DIM> -inline std::shared_ptr<Node> Producer(const std::array<DimSize_t, DIM> &dims, const std::string& name = "") { +inline std::shared_ptr<Node> Producer(const std::array<DimSize_t, DIM> &dims, const std::string& name = "", bool constant = false) { static_assert(DIM<=MaxDim,"Too many tensor dimensions required by Producer, not supported"); - return std::make_shared<Node>(std::make_shared<Producer_Op>(dims), name); + return std::make_shared<Node>(std::make_shared<Producer_Op>(dims, constant), name); } // helper with C-style array instead of std::array for kernel_dims to allow automatic template DIM deduction template <std::size_t DIM> -inline std::shared_ptr<Node> Producer(DimSize_t const (&dims)[DIM], const std::string& name = "") { - return Producer(to_array(dims), name); +inline std::shared_ptr<Node> Producer(DimSize_t const (&dims)[DIM], const std::string& name = "", bool constant = false) { + return Producer(to_array(dims), name, constant); } -inline std::shared_ptr<Node> Producer(const std::shared_ptr<Tensor> tensor, const std::string& name = "") { - return std::make_shared<Node>(std::make_shared<Producer_Op>(tensor), name); +inline std::shared_ptr<Node> Producer(const std::shared_ptr<Tensor> tensor, const std::string& name = "", bool constant = false) { + return std::make_shared<Node>(std::make_shared<Producer_Op>(tensor, constant), name); } template <std::array<DimSize_t, 1>::size_type DIM> @@ -130,4 +154,10 @@ void addProducer(std::shared_ptr<Node>& otherNode, const IOIndex_t inputIdx, Dim } } // namespace Aidge -#endif /* AIDGE_CORE_OPERATOR_PRODUCER_H_ */ \ No newline at end of file +namespace { +template <> +const char *const EnumStrings<Aidge::ProdAttr>::data[] = { + "Constant" +}; +} +#endif /* AIDGE_CORE_OPERATOR_PRODUCER_H_ */ diff --git a/python_binding/data/pybind_Tensor.cpp b/python_binding/data/pybind_Tensor.cpp index fa109a9af4b1146b60f0fffc80b8dfc6e4a2c256..688a519e593dcde1fe69e3324c81163250eeb42b 100644 --- a/python_binding/data/pybind_Tensor.cpp +++ b/python_binding/data/pybind_Tensor.cpp @@ -42,7 +42,7 @@ void addCtor(py::class_<Tensor, std::set<std::string> availableBackends = Tensor::getAvailableBackends(); if (availableBackends.find("cpu") != availableBackends.end()){ newTensor->setBackend("cpu"); - newTensor->getImpl()->setRawPtr(static_cast<T*>(info.ptr), newTensor->size()); + newTensor->getImpl()->copyFromHost(static_cast<T*>(info.ptr), newTensor->size()); }else{ printf("Warning : Could not use aidge_cpu backend, verify you have `import aidge_cpu`\n"); } @@ -95,7 +95,9 @@ void init_Tensor(py::module& m){ case DataType::Float32: return py::cast(b.get<float>(idx)); case DataType::Int32: - return py::cast(b.get<int>(idx)); + return py::cast(b.get<std::int32_t>(idx)); + case DataType::Int64: + return py::cast(b.get<std::int64_t>(idx)); default: return py::none(); } @@ -108,7 +110,9 @@ void init_Tensor(py::module& m){ case DataType::Float32: return py::cast(b.get<float>(coordIdx)); case DataType::Int32: - return py::cast(b.get<int>(coordIdx)); + return py::cast(b.get<std::int32_t>(coordIdx)); + case DataType::Int64: + return py::cast(b.get<std::int64_t>(coordIdx)); default: return py::none(); } @@ -137,7 +141,10 @@ void init_Tensor(py::module& m){ dataFormatDescriptor = py::format_descriptor<float>::format(); break; case DataType::Int32: - dataFormatDescriptor = py::format_descriptor<int>::format(); + dataFormatDescriptor = py::format_descriptor<std::int32_t>::format(); + break; + case DataType::Int64: + dataFormatDescriptor = py::format_descriptor<std::int64_t>::format(); break; default: throw py::value_error("Unsupported data format"); @@ -155,7 +162,8 @@ void init_Tensor(py::module& m){ // TODO : If the ctor with the right data type does not exist, pybind will always convert the data to INT ! // Need to find a way to avoid this ! - addCtor<int>(pyClassTensor); + addCtor<std::int32_t>(pyClassTensor); + addCtor<std::int64_t>(pyClassTensor); addCtor<float>(pyClassTensor); // #if SIZE_MAX != 0xFFFFFFFF addCtor<double>(pyClassTensor); diff --git a/python_binding/operator/pybind_MetaOperatorDefs.cpp b/python_binding/operator/pybind_MetaOperatorDefs.cpp index f5c5145e0a86d939b96e6d2a579dfa2579f8b3a5..b043ac23c378b9d591b7d1273ebcb5d48a37394a 100644 --- a/python_binding/operator/pybind_MetaOperatorDefs.cpp +++ b/python_binding/operator/pybind_MetaOperatorDefs.cpp @@ -122,7 +122,7 @@ 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()) + py::class_<MetaOperator_Op, std::shared_ptr<MetaOperator_Op>, OperatorTensor>(m, "MetaOperator_Op", py::multiple_inheritance()) .def("get_micro_graph", &MetaOperator_Op::getMicroGraph); m.def("meta_operator", &MetaOperator, diff --git a/python_binding/operator/pybind_OperatorTensor.cpp b/python_binding/operator/pybind_OperatorTensor.cpp index ce34dea158e6df1466db415b2539962c2113d42b..386a3af6c7c6e9dfad34ec2e56189a53797b59d9 100644 --- a/python_binding/operator/pybind_OperatorTensor.cpp +++ b/python_binding/operator/pybind_OperatorTensor.cpp @@ -21,6 +21,9 @@ void init_OperatorTensor(py::module& m){ py::class_<OperatorTensor, std::shared_ptr<OperatorTensor>, Operator>(m, "OperatorTensor") .def("get_output", &OperatorTensor::getOutput, py::arg("outputIdx")) .def("get_input", &OperatorTensor::getInput, py::arg("inputIdx")) + + .def("set_output", (void (OperatorTensor::*)(const IOIndex_t, const std::shared_ptr<Data>&)) &OperatorTensor::setOutput, py::arg("outputIdx"), py::arg("data")) + .def("set_input", (void (OperatorTensor::*)(const IOIndex_t, const std::shared_ptr<Data>&)) &OperatorTensor::setInput, py::arg("outputIdx"), py::arg("data")) .def("output_dims_forwarded", &OperatorTensor::outputDimsForwarded) ; } diff --git a/python_binding/operator/pybind_Producer.cpp b/python_binding/operator/pybind_Producer.cpp index 3dae24b620fe99098205d7d5f23591780f1e9cb7..78d9ce3489a8309c42cc90189e588a448fd9649a 100644 --- a/python_binding/operator/pybind_Producer.cpp +++ b/python_binding/operator/pybind_Producer.cpp @@ -24,20 +24,20 @@ namespace Aidge { template <DimIdx_t DIM> void declare_Producer(py::module &m) { // m.def(("Producer_" + std::to_string(DIM)+"D").c_str(), py::overload_cast<shared_ptr<Node>&>(&Producer<DIM>), py::arg("dims"), py::arg("name")); - m.def("Producer", static_cast<std::shared_ptr<Node>(*)(const std::array<DimSize_t, DIM>&, const std::string&)>(&Producer), py::arg("dims"), py::arg("name") = ""); + m.def("Producer", static_cast<std::shared_ptr<Node>(*)(const std::array<DimSize_t, DIM>&, const std::string&, bool)>(&Producer), py::arg("dims"), py::arg("name") = "", py::arg("constant") = false); } void init_Producer(py::module &m) { - py::class_<Producer_Op, std::shared_ptr<Producer_Op>, OperatorTensor>( + py::class_<Producer_Op, std::shared_ptr<Producer_Op>, OperatorTensor, Attributes>( m, "ProducerOp", py::multiple_inheritance()) .def("dims", &Producer_Op::dims) .def("get_inputs_name", &Producer_Op::getInputsName) .def("get_outputs_name", &Producer_Op::getOutputsName); - m.def("Producer", static_cast<std::shared_ptr<Node>(*)(const std::shared_ptr<Tensor>, const std::string&)>(&Producer), py::arg("tensor"), py::arg("name") = ""); + m.def("Producer", static_cast<std::shared_ptr<Node>(*)(const std::shared_ptr<Tensor>, const std::string&, bool)>(&Producer), py::arg("tensor"), py::arg("name") = "", py::arg("constant") = false); declare_Producer<1>(m); declare_Producer<2>(m); diff --git a/src/operator/Producer.cpp b/src/operator/Producer.cpp index 443f2fa7d8a60cd25ccb622f2dad5b4926b88eea..7bccbe763b90f2697997a889b30b610e4b531334 100644 --- a/src/operator/Producer.cpp +++ b/src/operator/Producer.cpp @@ -13,4 +13,4 @@ #include "aidge/operator/Producer.hpp" -const std::string Aidge::Producer_Op::Type = "Producer"; \ No newline at end of file +const std::string Aidge::Producer_Op::Type = "Producer";