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

Merged with main

parents d376906b 71763994
No related branches found
No related tags found
No related merge requests found
Showing
with 488 additions and 110 deletions
......@@ -34,6 +34,7 @@ public:
static std::map<Key, std::function<Func>>& registry()
{
#ifdef PYBIND
#define _CRT_SECURE_NO_WARNINGS
if (std::getenv("AIDGE_CORE_WITH_PYBIND")){
std::string name = std::string("registrar_")+typeid(Registrable<DerivedClass, Key, Func>).name();
static auto shared_data = reinterpret_cast<std::map<Key, std::function<Func>> *>(py::get_shared_data(name));
......
/********************************************************************************
* 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_UTILS_PARAMETER_H_
#define AIDGE_CORE_UTILS_PARAMETER_H_
#ifdef PYBIND
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <string> // Add this inclue to print error
#endif
#include <tuple>
#include <cassert>
#include <cstddef>
#ifdef PYBIND
namespace py = pybind11;
#endif
namespace {
// This is the type that will hold all the strings. Each enumerate type will
// declare its own specialization.
template <typename T> struct EnumStrings {
static const char* const data[];
};
}
namespace Aidge {
template<class T, std::size_t N>
constexpr std::size_t size(T (&)[N]) { return N; }
#ifdef PYBIND
/* This abstract class allows to avoid binding Parametrizable.
* Otherwise we would need to bind every template possible of Parametrizable.
* Every operators can access the methods of this class by inheriting from
* PyAbstractParametrizable in the binding code.
*/
class PyAbstractParametrizable{
public:
/* Bindable get function, does not recquire any templating.
* This is thanks to py::object which allow the function to
* be agnostic from its return type.
*/
virtual py::object getPy(const char* /*name*/) = 0;
};
#endif
template <class PARAM_ENUM, class ...T>
class Parameterizable
#ifdef PYBIND
: public PyAbstractParametrizable
#endif
{
public:
using Parameters = std::tuple<T...>;
// Helper class to pass to the constructor
template <PARAM_ENUM paramEnum>
class param {
public:
constexpr param(const typename std::tuple_element<static_cast<std::size_t>(paramEnum),std::tuple<T...>>::type& v) : value(v) {}
const typename std::tuple_element<static_cast<std::size_t>(paramEnum),std::tuple<T...>>::type value;
};
/*
// Direct tuple initialization
Parameterizable(T... params) : mParams({params...}) {
}
*/
// Constructor for parameters initialization.
// Compile-time garantee that every parameter is initialized.
template <PARAM_ENUM ...paramEnum> // non-type parameter pack
constexpr Parameterizable(const param<paramEnum>&&... params) {
// Check number of params consistency
static_assert(sizeof...(params) == std::tuple_size<std::tuple<T...>>::value, "wrong number of parameters in constructor");
// static_assert(size(EnumStrings<PARAM_ENUM>::data) == std::tuple_size<std::tuple<T...>>::value, "wrong number of parameters in enum string");
// Check no duplicates
constexpr std::array<PARAM_ENUM, std::tuple_size<std::tuple<T...>>::value> pe = { paramEnum... };
static_assert(!hasDuplicates(pe), "duplicate parameter"); // requires C++14
// Init params with constructor arguments
const std::array<PARAM_ENUM, std::tuple_size<std::tuple<T...>>::value> p = { ((void)(get<paramEnum>() = params.value), paramEnum) ... };
(void)p; // avoid unused warning
}
// Compile-time access with enum
template <PARAM_ENUM paramEnum>
constexpr typename std::tuple_element<static_cast<std::size_t>(paramEnum),std::tuple<T...>>::type& get() {
return std::get<static_cast<std::size_t>(paramEnum)>(mParams);
}
template <PARAM_ENUM paramEnum>
constexpr const typename std::tuple_element<static_cast<std::size_t>(paramEnum),std::tuple<T...>>::type& get() const {
return std::get<static_cast<std::size_t>(paramEnum)>(mParams);
}
// Runtime access with enum
template <typename R>
constexpr R& get(PARAM_ENUM paramEnum) {
return get<R>(static_cast<std::size_t>(paramEnum));
}
template <typename R>
constexpr const R& get(PARAM_ENUM paramEnum) const {
return get<R>(static_cast<std::size_t>(paramEnum));
}
// Runtime existance check with name
constexpr bool isParam(const char* name) const {
for (std::size_t i = 0; i < size(EnumStrings<PARAM_ENUM>::data); ++i) {
if (strcmp(EnumStrings<PARAM_ENUM>::data[i], name) == 0) {
return true;
}
}
return false;
}
// Runtime access with name
template <typename R>
constexpr R& get(const char* name) {
for (std::size_t i = 0; i < size(EnumStrings<PARAM_ENUM>::data); ++i) {
if (strcmp(EnumStrings<PARAM_ENUM>::data[i], name) == 0) {
return get<R>(i);
}
}
assert(false && "parameter not found");
}
template <typename R, std::size_t SIZE = std::tuple_size<std::tuple<T...>>::value-1>
constexpr typename std::enable_if<(SIZE > 0), R&>::type get(std::size_t i) {
if (i == SIZE) {
if (std::is_same<R, typename std::tuple_element<SIZE,std::tuple<T...>>::type>::value) {
return reinterpret_cast<R&>(std::get<SIZE>(mParams));
}
else {
assert(false && "wrong parameter type");
}
}
else {
return get<R, SIZE-1>(i);
}
}
template <typename R, std::size_t SIZE = std::tuple_size<std::tuple<T...>>::value-1>
constexpr typename std::enable_if<(SIZE <= 0), R&>::type get(std::size_t i) {
assert(false && "parameter not found");
}
constexpr const std::tuple<T...>& getParams() const {
return mParams;
}
#ifdef PYBIND
py::object getPy(const char* name){
for (std::size_t i = 0; i < size(EnumStrings<PARAM_ENUM>::data); ++i) {
if (strcmp(EnumStrings<PARAM_ENUM>::data[i], name) == 0) {
// https://github.com/pybind/pybind11/blob/f3e0602802c7840992c97f4960515777cad6a5c7/include/pybind11/pytypes.h#L1119-L1138
// Normal accessor would not work has we convert the tuple to a py::object which can be anything
return py::detail::accessor_policies::tuple_item::get(py::cast(mParams), static_cast<py::size_t>(i));
}
}
throw py::value_error("Parameter : " + std::string(name) + " does not exist." );
};
#endif
private:
template <typename V, std::size_t N>
static constexpr bool hasDuplicates(const std::array<V, N>& array) {
for (std::size_t i = 1; i < N; i++) {
for (std::size_t j = 0; j < i; j++) {
if (array[i] == array[j]) {
return true;
}
}
}
return false;
}
std::tuple<T...> mParams;
};
}
#endif /* AIDGE_CORE_UTILS_PARAMETER_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_UTILS_STATICATTRIBUTES_H_
#define AIDGE_CORE_UTILS_STATICATTRIBUTES_H_
#include <tuple>
#include <cassert>
#include <cstddef>
#include <typeinfo>
#include "aidge/utils/Attributes.hpp"
#include "aidge/utils/Utils.hpp"
namespace Aidge {
/**
* @brief This class is designed to handle static attributes (i.e. known at compile-time)
* with named accessors, with minimal overhead (the name strings are not stored in each object
* instance and it remains possible to access attribute without overhead at compile-time).
*/
template <class ATTRS_ENUM, class ...T>
class StaticAttributes : public Attributes {
public:
using Attrs = std::tuple<T...>;
// Helper class to pass to the constructor
template <ATTRS_ENUM attrsEnum>
class attr {
public:
constexpr attr(const typename std::tuple_element<static_cast<std::size_t>(attrsEnum),std::tuple<T...>>::type& v) : value(v) {}
const typename std::tuple_element<static_cast<std::size_t>(attrsEnum),std::tuple<T...>>::type value;
};
/*
// Direct tuple initialization
StaticAttributes(T... attrs) : mAttrs({attrs...}) {
}
*/
// Constructor for Attributes initialization.
// Compile-time garantee that every attribute is initialized.
template <ATTRS_ENUM ...attrsEnum> // non-type attribute pack
constexpr StaticAttributes(const attr<attrsEnum>&&... attrs) {
// Check number of attrs consistency
static_assert(sizeof...(attrs) == std::tuple_size<std::tuple<T...>>::value, "wrong number of attributes in constructor");
// static_assert(size(EnumStrings<ATTRS_ENUM>::data) == std::tuple_size<std::tuple<T...>>::value, "wrong number of attributes in enum string");
// Check no duplicates
constexpr std::array<ATTRS_ENUM, std::tuple_size<std::tuple<T...>>::value> pe = { attrsEnum... };
static_assert(!hasDuplicates(pe), "duplicate attribute"); // requires C++14
// Init attrs with constructor arguments
const std::array<ATTRS_ENUM, std::tuple_size<std::tuple<T...>>::value> p = { ((void)(getAttr<attrsEnum>() = attrs.value), attrsEnum) ... };
(void)p; // avoid unused warning
}
// Compile-time access with enum
template <ATTRS_ENUM attrsEnum>
constexpr typename std::tuple_element<static_cast<std::size_t>(attrsEnum),std::tuple<T...>>::type& getAttr() {
return std::get<static_cast<std::size_t>(attrsEnum)>(mAttrs);
}
template <ATTRS_ENUM attrsEnum>
constexpr const typename std::tuple_element<static_cast<std::size_t>(attrsEnum),std::tuple<T...>>::type& getAttr() const {
return std::get<static_cast<std::size_t>(attrsEnum)>(mAttrs);
}
// Runtime access with enum
template <typename R>
constexpr R& getAttr(ATTRS_ENUM attrsEnum) {
return getAttr<R>(static_cast<std::size_t>(attrsEnum));
}
template <typename R>
constexpr const R& getAttr(ATTRS_ENUM attrsEnum) const {
return getAttr<R>(static_cast<std::size_t>(attrsEnum));
}
// Runtime access with name
template <typename R>
constexpr R& getAttr(const char* name) {
for (std::size_t i = 0; i < size(EnumStrings<ATTRS_ENUM>::data); ++i) {
if (strcmp(EnumStrings<ATTRS_ENUM>::data[i], name) == 0) {
return getAttr<R>(i);
}
}
AIDGE_THROW_OR_ABORT(std::runtime_error, "attribute \"%s\" not found", name);
}
template <typename R, std::size_t SIZE = std::tuple_size<std::tuple<T...>>::value>
constexpr typename std::enable_if<(SIZE > 0), R&>::type getAttr(std::size_t i) {
if (i == SIZE-1) {
if (std::is_same<R, typename std::tuple_element<SIZE-1,std::tuple<T...>>::type>::value) {
return reinterpret_cast<R&>(std::get<SIZE-1>(mAttrs));
}
else {
AIDGE_THROW_OR_ABORT(std::runtime_error, "wrong type for attribute with index %lu", i);
}
}
else {
return getAttr<R, SIZE-1>(i);
}
}
template <typename R, std::size_t SIZE = std::tuple_size<std::tuple<T...>>::value>
[[noreturn]] constexpr typename std::enable_if<(SIZE == 0), R&>::type getAttr(std::size_t /*i*/) {
AIDGE_THROW_OR_ABORT(std::runtime_error, "attribute not found");
}
template <std::size_t SIZE = std::tuple_size<std::tuple<T...>>::value>
constexpr typename std::enable_if<(SIZE > 0), const std::type_info&>::type getAttrType(std::size_t i) const {
if (i == SIZE-1) {
return typeid(typename std::tuple_element<SIZE-1,std::tuple<T...>>::type);
}
else {
return getAttrType<SIZE-1>(i);
}
}
template <std::size_t SIZE = std::tuple_size<std::tuple<T...>>::value>
[[noreturn]] constexpr typename std::enable_if<(SIZE == 0), const std::type_info&>::type getAttrType(std::size_t /*i*/) const {
AIDGE_THROW_OR_ABORT(std::runtime_error, "attribute not found");
}
constexpr const std::tuple<T...>& getStaticAttributes() const {
return mAttrs;
}
//////////////////////////////////////
/// Generic Attributes API
//////////////////////////////////////
// Runtime existance check with name
constexpr bool hasAttr(const std::string& name) const override final {
for (std::size_t i = 0; i < size(EnumStrings<ATTRS_ENUM>::data); ++i) {
if (name == EnumStrings<ATTRS_ENUM>::data[i]) {
return true;
}
}
return false;
}
// Runtime type access with name
constexpr std::string getAttrType(const std::string& name) const override final {
for (std::size_t i = 0; i < size(EnumStrings<ATTRS_ENUM>::data); ++i) {
if (name == EnumStrings<ATTRS_ENUM>::data[i]) {
return getAttrType(i).name();
}
}
AIDGE_THROW_OR_ABORT(std::runtime_error, "attribute \"%s\" not found", name.c_str());
}
std::set<std::string> getAttrsName() const override final {
std::set<std::string> attrsName;
for (std::size_t i = 0; i < size(EnumStrings<ATTRS_ENUM>::data); ++i) {
attrsName.insert(EnumStrings<ATTRS_ENUM>::data[i]);
}
return attrsName;
}
#ifdef PYBIND
py::object getAttrPy(const std::string& name) const {
for (std::size_t i = 0; i < size(EnumStrings<ATTRS_ENUM>::data); ++i) {
if (name == EnumStrings<ATTRS_ENUM>::data[i]) {
// https://github.com/pybind/pybind11/blob/f3e0602802c7840992c97f4960515777cad6a5c7/include/pybind11/pytypes.h#L1119-L1138
// Normal accessor would not work has we convert the tuple to a py::object which can be anything
return py::detail::accessor_policies::tuple_item::get(py::cast(mAttrs), static_cast<py::size_t>(i));
}
}
AIDGE_THROW_OR_ABORT(py::value_error, "attribute \"%s\" not found", name.c_str());
};
#endif
private:
template <typename V, std::size_t N>
static constexpr bool hasDuplicates(const std::array<V, N>& array) {
for (std::size_t i = 1; i < N; i++) {
for (std::size_t j = 0; j < i; j++) {
if (array[i] == array[j]) {
return true;
}
}
}
return false;
}
std::tuple<T...> mAttrs;
};
}
#endif /* AIDGE_CORE_UTILS_STATICATTRIBUTES_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_UTILS_TENSOR_UTILS_H_
#define AIDGE_CORE_UTILS_TENSOR_UTILS_H_
#include <cmath> // std::abs
#include "aidge/data/Tensor.hpp"
/**
* @brief Compare two :cpp:class:`Aidge::Tensor` value wise. The comparison function is:
*
* |t1-t2| <= absolute + relative * |t2|
*
* If a tensor value is different from the other tensor return False
* If the tensor does not have the same size, return False
* If the datatype is not the same between each tensor return False
* If the templated type does not correspond to the datatype of each tensor, raise an assertion error
*
* @tparam T should correspond to the type of the tensor, define the type of the absolute and relative error
* @param t1 first :cpp:class:`Aidge::Tensor` to test
* @param t2 second :cpp:class:`Aidge::Tensor` to test
* @param relative relative difference allowed (should be betwen 0 and 1)
* @param absolute absolute error allowed (shoulmd be positive)
* @return true if both tensor are approximately equal and have the datatype, shape. Else return false
*/
template <typename T>
bool approxEq(Aidge::Tensor t1, Aidge::Tensor t2, float relative, float absolute){
assert(t1.dataType() == t2.dataType());
assert(t1.dataType() == NativeType<T>::type);
assert(relative >= 0);
assert(absolute >= 0 && absolute<=1);
if (t1.size() != t2.size()){
return false;
}
for(size_t i; i < t1.size(); ++i){
if (static_cast<float>(std::abs(t1.get<T>(i) - t2.get<T>(i))) > (absolute + (relative * static_cast<float>(std::abs(t2.get<T>(i)))))){
return false;
}
}
return true;
}
#endif /* AIDGE_CORE_UTILS_TENSOR_UTILS_H_s */
/********************************************************************************
* 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_UTILS_H_
#define AIDGE_UTILS_H_
#include <cstdio>
#ifdef NO_EXCEPTIONS
#define AIDGE_THROW_OR_ABORT(ex, ...) \
do { std::printf(__VA_ARGS__); std::abort(); } while (false)
#else
#include <stdexcept>
#include <memory>
#define AIDGE_THROW_OR_ABORT(ex, ...) \
do { \
int n = 128; \
std::unique_ptr<char[]> formatted; \
formatted.reset(new char[n]); \
const int len = std::snprintf(formatted.get(), n, __VA_ARGS__); \
if (len >= n) { \
formatted.reset(new char[len + 1]); \
std::snprintf(formatted.get(), len + 1, __VA_ARGS__); \
}; \
throw ex(formatted.get()); \
} while (false)
#endif
#endif //AIDGE_UTILS_H_
\ No newline at end of file
......@@ -26,10 +26,10 @@ namespace Aidge {
template<typename T>
void addCtor(py::class_<Tensor,
std::shared_ptr<Tensor>,
Data,
std::shared_ptr<Tensor>,
Data,
Registrable<Tensor,
std::tuple<std::string, DataType>,
std::tuple<std::string, DataType>,
std::unique_ptr<TensorImpl>(const Tensor&)>>& mTensor){
mTensor.def(py::init([]( py::array_t<T, py::array::c_style | py::array::forcecast> b) {
/* Request a buffer descriptor from Python */
......@@ -46,24 +46,27 @@ void addCtor(py::class_<Tensor,
}else{
printf("Warning : Could not use aidge_cpu backend, verify you have `import aidge_cpu`\n");
}
return newTensor;
}));
}))
.def("__setitem__", (void (Tensor::*)(std::size_t, T)) &Tensor::set)
.def("__setitem__", (void (Tensor::*)(std::vector<std::size_t>, T)) &Tensor::set)
;
}
void init_Tensor(py::module& m){
py::class_<Registrable<Tensor,
std::tuple<std::string, DataType>,
std::tuple<std::string, DataType>,
std::unique_ptr<TensorImpl>(const Tensor&)>,
std::shared_ptr<Registrable<Tensor,
std::tuple<std::string, DataType>,
std::tuple<std::string, DataType>,
std::unique_ptr<TensorImpl>(const Tensor&)>>>(m,"TensorRegistrable");
py::class_<Tensor, std::shared_ptr<Tensor>,
Data,
py::class_<Tensor, std::shared_ptr<Tensor>,
Data,
Registrable<Tensor,
std::tuple<std::string, DataType>,
std::tuple<std::string, DataType>,
std::unique_ptr<TensorImpl>(const Tensor&)>> pyClassTensor
(m,"Tensor", py::multiple_inheritance(), py::buffer_protocol());
......@@ -74,6 +77,8 @@ void init_Tensor(py::module& m){
.def("size", &Tensor::size)
.def("resize", (void (Tensor::*)(const std::vector<DimSize_t>&)) &Tensor::resize)
.def("has_impl", &Tensor::hasImpl)
.def("get_coord", &Tensor::getCoord)
.def("get_idx", &Tensor::getIdx)
.def_static("get_available_backends", &Tensor::getAvailableBackends)
.def("__str__", [](Tensor& b) {
return b.toString();
......@@ -82,15 +87,27 @@ void init_Tensor(py::module& m){
return b.size();
})
.def("__getitem__", [](Tensor& b, size_t idx)-> py::object {
// TODO : Should return error if backend not compatible with get
if (idx >= b.size()) throw py::index_error();
switch(b.dataType()){
case DataType::Float64:
return py::cast(static_cast<double*>(b.getImpl()->rawPtr())[idx]);
return py::cast(b.get<double>(idx));
case DataType::Float32:
return py::cast(b.get<float>(idx));
case DataType::Int32:
return py::cast(b.get<int>(idx));
default:
return py::none();
}
})
.def("__getitem__", [](Tensor& b, std::vector<size_t> coordIdx)-> py::object {
if (b.getIdx(coordIdx) >= b.size()) throw py::index_error();
switch(b.dataType()){
case DataType::Float64:
return py::cast(b.get<double>(coordIdx));
case DataType::Float32:
return py::cast(static_cast<float*>(b.getImpl()->rawPtr())[idx]);
return py::cast(b.get<float>(coordIdx));
case DataType::Int32:
return py::cast(static_cast<int*>(b.getImpl()->rawPtr())[idx]);
return py::cast(b.get<int>(coordIdx));
default:
return py::none();
}
......@@ -126,12 +143,12 @@ void init_Tensor(py::module& m){
}
return py::buffer_info(
tensorImpl->rawPtr(), /* Pointer to buffer */
tensorImpl->scalarSize(), /* Size of one scalar */
dataFormatDescriptor, /* Python struct-style format descriptor */
b.nbDims(), /* Number of dimensions */
dims, /* Buffer dimensions */
strides /* Strides (in bytes) for each index */
tensorImpl->rawPtr(), /* Pointer to buffer */
tensorImpl->scalarSize(), /* Size of one scalar */
dataFormatDescriptor, /* Python struct-style format descriptor */
b.nbDims(), /* Number of dimensions */
dims, /* Buffer dimensions */
strides /* Strides (in bytes) for each index */
);
});
......@@ -142,6 +159,6 @@ void init_Tensor(py::module& m){
// #if SIZE_MAX != 0xFFFFFFFF
addCtor<double>(pyClassTensor);
// #endif
}
}
......@@ -12,7 +12,6 @@
#include <pybind11/pybind11.h>
#include "aidge/operator/Add.hpp"
#include "aidge/utils/Parameter.hpp"
#include "aidge/backend/OperatorImpl.hpp"
#include "aidge/operator/Operator.hpp"
#include "aidge/utils/Types.h"
......
......@@ -16,7 +16,6 @@
#include <vector>
#include <array>
#include "aidge/utils/Parameter.hpp"
#include "aidge/backend/OperatorImpl.hpp"
#include "aidge/operator/AvgPooling.hpp"
#include "aidge/operator/Operator.hpp"
......@@ -27,7 +26,7 @@ namespace py = pybind11;
namespace Aidge {
template <DimIdx_t DIM> void declare_AvgPoolingOp(py::module &m) {
py::class_<AvgPooling_Op<DIM>, std::shared_ptr<AvgPooling_Op<DIM>>, Operator, PyAbstractParametrizable>(
py::class_<AvgPooling_Op<DIM>, std::shared_ptr<AvgPooling_Op<DIM>>, Operator, Attributes>(
m, ("AvgPoolingOp" + std::to_string(DIM) + "D").c_str(),
py::multiple_inheritance())
.def(py::init<const std::array<DimSize_t, DIM> &,
......
......@@ -14,7 +14,6 @@
#include "aidge/operator/BatchNorm.hpp"
#include "aidge/operator/Operator.hpp"
#include "aidge/utils/Parameter.hpp"
#include "aidge/utils/Types.h"
namespace py = pybind11;
......@@ -22,7 +21,7 @@ namespace Aidge {
template <DimSize_t DIM>
void declare_BatchNormOp(py::module& m) {
py::class_<BatchNorm_Op<DIM>, std::shared_ptr<BatchNorm_Op<DIM>>, Operator, PyAbstractParametrizable>(m, ("BatchNorm_Op" + std::to_string(DIM) + "D").c_str(), py::multiple_inheritance());
py::class_<BatchNorm_Op<DIM>, std::shared_ptr<BatchNorm_Op<DIM>>, Operator, Attributes>(m, ("BatchNorm_Op" + std::to_string(DIM) + "D").c_str(), py::multiple_inheritance());
m.def(("BatchNorm" + std::to_string(DIM) + "D").c_str(), &BatchNorm<DIM>, py::arg("epsilon") = 1.0e-5F, py::arg("momentum") = 0.1F, py::arg("name") = "");
}
......
......@@ -16,7 +16,6 @@
#include <vector>
#include <array>
#include "aidge/utils/Parameter.hpp"
#include "aidge/backend/OperatorImpl.hpp"
#include "aidge/operator/Conv.hpp"
#include "aidge/operator/Operator.hpp"
......@@ -26,7 +25,7 @@ namespace py = pybind11;
namespace Aidge {
template <DimIdx_t DIM> void declare_ConvOp(py::module &m) {
py::class_<Conv_Op<DIM>, std::shared_ptr<Conv_Op<DIM>>, Operator, PyAbstractParametrizable>(
py::class_<Conv_Op<DIM>, std::shared_ptr<Conv_Op<DIM>>, Operator, Attributes>(
m, ("ConvOp" + std::to_string(DIM) + "D").c_str(),
py::multiple_inheritance())
.def(py::init<DimSize_t,
......
......@@ -16,7 +16,6 @@
#include <vector>
#include <array>
#include "aidge/utils/Parameter.hpp"
#include "aidge/backend/OperatorImpl.hpp"
#include "aidge/operator/ConvDepthWise.hpp"
#include "aidge/operator/Operator.hpp"
......@@ -27,7 +26,7 @@ namespace py = pybind11;
namespace Aidge {
template <DimIdx_t DIM> void declare_ConvDepthWiseOp(py::module &m) {
py::class_<ConvDepthWise_Op<DIM>, std::shared_ptr<ConvDepthWise_Op<DIM>>, Operator, PyAbstractParametrizable>(
py::class_<ConvDepthWise_Op<DIM>, std::shared_ptr<ConvDepthWise_Op<DIM>>, Operator, Attributes>(
m, ("ConvDepthWiseOp" + std::to_string(DIM) + "D").c_str(),
py::multiple_inheritance())
.def(py::init<const std::array<DimSize_t, DIM> &,
......
......@@ -12,7 +12,6 @@
#include <pybind11/pybind11.h>
#include "aidge/operator/FC.hpp"
#include "aidge/utils/Parameter.hpp"
#include "aidge/backend/OperatorImpl.hpp"
#include "aidge/operator/Operator.hpp"
#include "aidge/utils/Types.h"
......@@ -21,7 +20,7 @@ namespace py = pybind11;
namespace Aidge {
void declare_FC(py::module &m) {
py::class_<FC_Op, std::shared_ptr<FC_Op>, Operator, PyAbstractParametrizable>(m, "FC_Op", py::multiple_inheritance());
py::class_<FC_Op, std::shared_ptr<FC_Op>, Operator, Attributes>(m, "FC_Op", py::multiple_inheritance());
m.def("FC", &FC, py::arg("out_channels"), py::arg("nobias") = false, py::arg("name") = "");
}
......
......@@ -11,6 +11,7 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include <stdio.h>
#include "aidge/backend/OperatorImpl.hpp"
......@@ -20,46 +21,11 @@ namespace py = pybind11;
namespace Aidge {
void init_GenericOperator(py::module& m) {
py::class_<GenericOperator_Op, std::shared_ptr<GenericOperator_Op>, Operator>(m, "GenericOperatorOp",
py::class_<GenericOperator_Op, std::shared_ptr<GenericOperator_Op>, Operator, DynamicAttributes>(m, "GenericOperatorOp",
py::multiple_inheritance())
.def("get_parameter_type", &GenericOperator_Op::getParameterType)
.def("get_parameters_name", &GenericOperator_Op::getParametersName)
.def("add_parameter", &GenericOperator_Op::addParameter<bool>)
.def("add_parameter", &GenericOperator_Op::addParameter<int>)
.def("add_parameter", &GenericOperator_Op::addParameter<float>)
.def("add_parameter", &GenericOperator_Op::addParameter<std::string>)
.def("add_parameter", &GenericOperator_Op::addParameter<std::vector<bool>>)
.def("add_parameter", &GenericOperator_Op::addParameter<std::vector<int>>)
.def("add_parameter", &GenericOperator_Op::addParameter<std::vector<float>>)
.def("add_parameter", &GenericOperator_Op::addParameter<std::vector<std::string>>)
.def("get_parameter", [](GenericOperator_Op& self, std::string key) -> py::object {
/*
This getParameter method returns the good python type without having to have
prior knowledge of the parameter type.
*/
py::object res = py::none();
std::string paramType = self.getParameterType(key);
if(paramType == typeid(int).name())
res = py::cast(self.getParameter<int>(key));
else if(paramType == typeid(float).name())
res = py::cast(self.getParameter<float>(key));
else if(paramType == typeid(bool).name())
res = py::cast(self.getParameter<bool>(key));
else if(paramType == typeid(std::string).name())
res = py::cast(self.getParameter<std::string>(key));
else if(paramType == typeid(std::vector<bool>).name())
res = py::cast(self.getParameter<std::vector<bool>>(key));
else if(paramType == typeid(std::vector<int>).name())
res = py::cast(self.getParameter<std::vector<int>>(key));
else if(paramType == typeid(std::vector<float>).name())
res = py::cast(self.getParameter<std::vector<float>>(key));
else if(paramType == typeid(std::vector<std::string>).name())
res = py::cast(self.getParameter<std::vector<std::string>>(key));
else {
throw py::key_error("Failed to convert parameter type " + key + ", this issue may come from typeid function which gave an unknown key : [" + paramType + "]. Please open an issue asking to add the support for this key.");
}
return res;
});
.def_readonly_static("identity", &GenericOperator_Op::Identity)
.def("compute_output_dims", &GenericOperator_Op::computeOutputDims)
.def("set_compute_output_dims", &GenericOperator_Op::setComputeOutputDims, py::arg("computation_function"));
m.def("GenericOperator", &GenericOperator, py::arg("type"), py::arg("nbDataIn"), py::arg("nbIn"), py::arg("nbOut"),
py::arg("name") = "");
......
......@@ -13,13 +13,12 @@
#include "aidge/operator/LeakyReLU.hpp"
#include "aidge/operator/Operator.hpp"
#include "aidge/utils/Parameter.hpp"
namespace py = pybind11;
namespace Aidge {
void init_LeakyReLU(py::module& m) {
py::class_<LeakyReLU_Op, std::shared_ptr<LeakyReLU_Op>, Operator, PyAbstractParametrizable>(m, "LeakyReLU_Op", py::multiple_inheritance());
py::class_<LeakyReLU_Op, std::shared_ptr<LeakyReLU_Op>, Operator, Attributes>(m, "LeakyReLU_Op", py::multiple_inheritance());
m.def("LeakyReLU", &LeakyReLU, py::arg("negative_slope") = 0.0f, py::arg("name") = "");
}
......
......@@ -11,8 +11,7 @@
#include <pybind11/pybind11.h>
#include "aidge/operator/Matmul.hpp"
#include "aidge/utils/Parameter.hpp"
#include "aidge/operator/MatMul.hpp"
#include "aidge/backend/OperatorImpl.hpp"
#include "aidge/operator/Operator.hpp"
#include "aidge/utils/Types.h"
......@@ -20,13 +19,13 @@
namespace py = pybind11;
namespace Aidge {
void declare_Matmul(py::module &m) {
py::class_<Matmul_Op, std::shared_ptr<Matmul_Op>, Operator, PyAbstractParametrizable>(m, "Matmul_Op", py::multiple_inheritance());
void declare_MatMul(py::module &m) {
py::class_<MatMul_Op, std::shared_ptr<MatMul_Op>, Operator, Attributes>(m, "MatMul_Op", py::multiple_inheritance());
m.def("Matmul", &Matmul, py::arg("out_channels"), py::arg("name") = "");
m.def("MatMul", &MatMul, py::arg("out_channels"), py::arg("name") = "");
}
void init_Matmul(py::module &m) {
declare_Matmul(m);
void init_MatMul(py::module &m) {
declare_MatMul(m);
}
} // namespace Aidge
......@@ -16,7 +16,6 @@
#include <vector>
#include <array>
#include "aidge/utils/Parameter.hpp"
#include "aidge/backend/OperatorImpl.hpp"
#include "aidge/operator/MaxPooling.hpp"
#include "aidge/operator/Operator.hpp"
......@@ -27,7 +26,7 @@ namespace py = pybind11;
namespace Aidge {
template <DimIdx_t DIM> void declare_MaxPoolingOp(py::module &m) {
py::class_<MaxPooling_Op<DIM>, std::shared_ptr<MaxPooling_Op<DIM>>, Operator, PyAbstractParametrizable>(
py::class_<MaxPooling_Op<DIM>, std::shared_ptr<MaxPooling_Op<DIM>>, Operator, Attributes>(
m, ("MaxPoolingOp" + std::to_string(DIM) + "D").c_str(),
py::multiple_inheritance())
.def(py::init<const std::array<DimSize_t, DIM> &,
......
......@@ -13,7 +13,6 @@
#include <pybind11/stl.h>
#include "aidge/utils/Types.h"
#include "aidge/utils/Parameter.hpp"
// #include "aidge/backend/OperatorImpl.hpp"
#include "aidge/operator/Operator.hpp"
#include "aidge/operator/Producer.hpp"
......@@ -26,18 +25,19 @@ 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") = "");
}
void init_Producer(py::module &m) {
py::class_<Producer_Op, std::shared_ptr<Producer_Op>, Operator>(
m,
"ProducerOp",
m,
"ProducerOp",
py::multiple_inheritance())
.def("dims", &Producer_Op::dims);
.def("dims", &Producer_Op::dims)
.def("set_output_tensor", &Producer_Op::setOutputTensor);
m.def("Producer", static_cast<std::shared_ptr<Node>(*)(const std::shared_ptr<Tensor>, const std::string&)>(&Producer), py::arg("tensor"), py::arg("name") = "");
declare_Producer<1>(m);
declare_Producer<2>(m);
declare_Producer<3>(m);
......
......@@ -17,7 +17,7 @@ namespace Aidge {
void init_Data(py::module&);
void init_Tensor(py::module&);
void init_OperatorImpl(py::module&);
void init_Parameterizable(py::module&);
void init_Attributes(py::module&);
void init_Operator(py::module&);
void init_Add(py::module&);
......@@ -28,7 +28,7 @@ void init_ConvDepthWise(py::module&);
void init_FC(py::module&);
void init_GenericOperator(py::module&);
void init_LeakyReLU(py::module&);
void init_Matmul(py::module&);
void init_MatMul(py::module&);
void init_MaxPooling(py::module&);
void init_Producer(py::module&);
void init_ReLU(py::module&);
......@@ -46,7 +46,7 @@ void init_GRegex(py::module&);
void init_Recipies(py::module&);
void init_Scheduler(py::module&);
void init_TensorUtils(py::module&);
void set_python_flag(){
// Set an env variable to know if we run with ypthon or cpp
......@@ -65,7 +65,7 @@ void init_Aidge(py::module& m){
init_Connector(m);
init_OperatorImpl(m);
init_Parameterizable(m);
init_Attributes(m);
init_Operator(m);
init_Add(m);
init_AvgPooling(m);
......@@ -75,7 +75,7 @@ void init_Aidge(py::module& m){
init_FC(m);
init_GenericOperator(m);
init_LeakyReLU(m);
init_Matmul(m);
init_MatMul(m);
init_MaxPooling(m);
init_ReLU(m);
init_Softmax(m);
......@@ -86,6 +86,7 @@ void init_Aidge(py::module& m){
init_GRegex(m);
init_Recipies(m);
init_Scheduler(m);
init_TensorUtils(m);
}
PYBIND11_MODULE(aidge_core, m) {
......
......@@ -20,24 +20,51 @@ namespace py = pybind11;
namespace Aidge {
void init_Recipies(py::module &m) {
m.def("fuse_mul_add", &fuseMulAdd, py::arg("nodes"), R"mydelimiter(
Recipie to Fuse MatMul and Add operators into an `aidge.FC` operator.
Parameters
----------
m.def("fuse_mul_add", static_cast<void(*)(std::shared_ptr<GraphView>)>(fuseMulAdd), py::arg("graph_view"), R"mydelimiter(
Recipie to Fuse MatMul and Add operators into an :py:class:`aidge_core.FC` operator.
:param graph_view: Graph view on which we want to apply the recipie
:type graph_view: :py:class:`aidge_core.GraphView`
)mydelimiter");
m.def("fuse_mul_add", static_cast<void(*)(std::set<std::shared_ptr<Node>>)>(fuseMulAdd), py::arg("nodes"), R"mydelimiter(
Recipie to Fuse MatMul and Add operators into an :py:class:`aidge_core.FC` operator.
:param nodes: The MatMul and Add nodes to fuse.
:type nodes: list of `aidge.node`
:type nodes: list of :py:class:`aidge_core.Node`
)mydelimiter");
m.def("remove_flatten", static_cast<void(*)(std::shared_ptr<GraphView>)>(removeFlatten), py::arg("graph_view"), R"mydelimiter(
Recipie to remove a flatten operator.
:param graph_view: Graph view on which we want to apply the recipie
:type graph_view: :py:class:`aidge_core.GraphView`
)mydelimiter");
m.def("remove_flatten", &removeFlatten, py::arg("nodes"), R"mydelimiter(
m.def("remove_flatten", static_cast<void(*)(std::set<std::shared_ptr<Node>>)>(removeFlatten), py::arg("nodes"), R"mydelimiter(
Recipie to remove a flatten operator.
Parameters
----------
:param nodes: The flatten operator to remove.
:type nodes: list of `aidge.node`
:type nodes: list of :py:class:`aidge_core.Node`
)mydelimiter");
m.def("fuse_mul_add", static_cast<void(*)(std::set<std::shared_ptr<Node>>)>(fuseMulAdd), py::arg("nodes"), R"mydelimiter(
Recipie to Fuse MatMul and Add operators into an :py:class:`aidge_core.FC` operator.
:param nodes: The MatMul and Add nodes to fuse.
:type nodes: list of :py:class:`aidge_core.Node`
)mydelimiter");
m.def("fuse_batchnorm", static_cast<void(*)(std::shared_ptr<GraphView>)>(fuseBatchNorm), py::arg("graph_view"), R"mydelimiter(
Recipie to remove a flatten operator.
:param graph_view: Graph view on which we want to apply the recipie
:type graph_view: :py:class:`aidge_core.GraphView`
)mydelimiter");
m.def("fuse_batchnorm", static_cast<void(*)(std::set<std::shared_ptr<Node>>)>(fuseBatchNorm), py::arg("nodes"), R"mydelimiter(
Recipie to remove a flatten operator.
:param nodes: The flatten operator to remove.
:type nodes: list of :py:class:`aidge_core.Node`
)mydelimiter");
}
} // namespace Aidge
#include <pybind11/pybind11.h>
#include "aidge/utils/Parameter.hpp"
#include "aidge/utils/Attributes.hpp"
#include "aidge/utils/DynamicAttributes.hpp"
namespace py = pybind11;
namespace Aidge {
void init_Parameterizable(py::module& m){
py::class_<PyAbstractParametrizable, std::shared_ptr<PyAbstractParametrizable>>(m, "PyAbstractParametrizable")
.def("get", &PyAbstractParametrizable::getPy, py::arg("name"))
;
DynamicAttributes test_DynamicAttributes_binding() {
DynamicAttributes attrs;
attrs.addAttr<int>("a", 42);
attrs.addAttr<std::string>("b", "test");
attrs.addAttr<std::vector<bool>>("c", {true, false, true});
return attrs;
}
double test_DynamicAttributes_binding_check(DynamicAttributes& attrs) {
return attrs.getAttr<double>("d");
}
void init_Attributes(py::module& m){
py::class_<Attributes, std::shared_ptr<Attributes>>(m, "Attributes")
.def("has_attr", &Attributes::hasAttr, py::arg("name"))
.def("get_attr_type", &Attributes::getAttrType, py::arg("name"))
.def("get_attrs_name", &Attributes::getAttrsName)
.def("get_attr", &Attributes::getAttrPy, py::arg("name"));
py::class_<DynamicAttributes, std::shared_ptr<DynamicAttributes>, Attributes>(m, "DynamicAttributes")
.def("add_attr", &DynamicAttributes::addAttrPy, py::arg("name"), py::arg("value"))
.def("set_attr", &DynamicAttributes::setAttrPy, py::arg("name"), py::arg("value"))
.def("del_attr", &DynamicAttributes::delAttr, py::arg("name"));
m.def("test_DynamicAttributes_binding", &test_DynamicAttributes_binding);
m.def("test_DynamicAttributes_binding_check", &test_DynamicAttributes_binding_check, py::arg("attrs"));
}
}
/********************************************************************************
* 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 <pybind11/stl.h>
#include <string>
#include "aidge/utils/TensorUtils.hpp"
namespace py = pybind11;
namespace Aidge {
template<typename T>
void addTensorUtilsFunction(py::module &m){
m.def("approx_eq",
& approxEq<T>,
py::arg("t1"),
py::arg("t2"),
py::arg("relative"),
py::arg("absolute"),
R"mydelimiter(
Compare two :cpp:class:`Aidge::Tensor` value wise. The comparison function is:
|t1-t2| <= absolute + relative * |t2|
If a tensor value is different from the other tensor return False
If the tensor does not have the same size, return False
If the datatype is not the same between each tensor return False
If the templated type does not correspond to the datatype of each tensor, raise an assertion error
:param t1: first tensor to test
:type t1: :py:class:`aidge_core.Tensor`
:param t2: second tensor to test
:type t2: :py:class:`aidge_core.Tensor`
:param relative: relative difference allowed (should be betwen 0 and 1)
:type relative: float
:param absolute: absolute error allowed (shoulmd be positive)
:type absolute: float
)mydelimiter");
}
void init_TensorUtils(py::module &m) {
addTensorUtilsFunction<float>(m);
addTensorUtilsFunction<double>(m);
addTensorUtilsFunction<int>(m);
addTensorUtilsFunction<long>(m);
}
} // 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