diff --git a/.gitlab/ci/build.gitlab-ci.yml b/.gitlab/ci/build.gitlab-ci.yml index da0d23c9de978ebcdbb370a6f4a92262829e05b9..73b85c8a409e675c849b9ca66557c63b5acf6359 100644 --- a/.gitlab/ci/build.gitlab-ci.yml +++ b/.gitlab/ci/build.gitlab-ci.yml @@ -12,6 +12,7 @@ build:ubuntu_cpp: - make -j4 all install artifacts: + expire_in: 1 week paths: - build_cpp/ - install_cpp/ @@ -29,6 +30,7 @@ build:ubuntu_python: - export AIDGE_INSTALL=`pwd`/install - python3 -m pip install . artifacts: + expire_in: 1 week paths: - venv/ @@ -57,6 +59,7 @@ build:windows_cpp: - cmake --install . --config Debug artifacts: + expire_in: 1 week paths: - build_cpp/ - install_cpp/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a4899b4759864d1f6cf38ab0d8dea3dae8026f5..f65c32016b40d6e8ca9601b39815a98dc10943f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,9 +52,9 @@ target_include_directories(${module_name} ) # PYTHON BINDING -generate_python_binding(${project} ${module_name}) - if (PYBIND) + generate_python_binding(${project} ${module_name}) + # Handles Python + pybind11 headers dependencies target_link_libraries(${module_name} PUBLIC @@ -72,21 +72,13 @@ else() set(SANITIZE_FLAGS -fsanitize=address,leak,undefined,float-divide-by-zero -fno-omit-frame-pointer) endif() -if(WERROR) target_compile_options(${module_name} PRIVATE $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:GNU>>: - -Wall -Wextra -fPIC -Wold-style-cast -Winline -pedantic -Werror=narrowing -Wshadow -Werror ${SANITIZE_FLAGS}>) + -Wall -Wextra -fPIC -Wold-style-cast -Winline -pedantic -Werror=narrowing -Wshadow $<$<BOOL:${WERROR}>:-Werror> ${SANITIZE_FLAGS}>) target_compile_options(${module_name} PRIVATE $<$<CXX_COMPILER_ID:MSVC>: /W4>) -else() - target_compile_options(${module_name} PRIVATE - $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:GNU>>: - -Wall -Wextra -fPIC -Wold-style-cast -Winline -pedantic -Werror=narrowing -Wshadow -Wpedantic ${SANITIZE_FLAGS}>) - target_compile_options(${module_name} PRIVATE - $<$<CXX_COMPILER_ID:MSVC>: - /W4>) -endif() + target_link_options(${module_name} PUBLIC ${SANITIZE_FLAGS}) if(CMAKE_COMPILER_IS_GNUCXX AND COVERAGE) diff --git a/cmake/PybindModuleCreation.cmake b/cmake/PybindModuleCreation.cmake index 18f4abc38e2537c3f4d949f08772a57b90758cb0..8030c1a8639e4b7ae0c5fb865e928a4260c6ae7d 100644 --- a/cmake/PybindModuleCreation.cmake +++ b/cmake/PybindModuleCreation.cmake @@ -1,23 +1,21 @@ -function(generate_python_binding name target_to_bind) - if (PYBIND) - add_definitions(-DPYBIND) - Include(FetchContent) +function(generate_python_binding name target_to_bind) + add_definitions(-DPYBIND) + Include(FetchContent) - FetchContent_Declare( - PyBind11 - GIT_REPOSITORY https://github.com/pybind/pybind11.git - GIT_TAG v2.10.4 # or a later release - ) + FetchContent_Declare( + PyBind11 + GIT_REPOSITORY https://github.com/pybind/pybind11.git + GIT_TAG v2.10.4 # or a later release + ) - # Use the New FindPython mode, recommanded. Requires CMake 3.15+ - find_package(Python COMPONENTS Interpreter Development) - FetchContent_MakeAvailable(PyBind11) + # Use the New FindPython mode, recommanded. Requires CMake 3.15+ + find_package(Python COMPONENTS Interpreter Development) + FetchContent_MakeAvailable(PyBind11) - message(STATUS "Creating binding for module ${name}") - file(GLOB_RECURSE pybind_src_files "python_binding/*.cpp") + message(STATUS "Creating binding for module ${name}") + file(GLOB_RECURSE pybind_src_files "python_binding/*.cpp") - pybind11_add_module(${name} MODULE ${pybind_src_files} "NO_EXTRAS") # NO EXTRA recquired for pip install - target_include_directories(${name} PUBLIC "python_binding") - target_link_libraries(${name} PUBLIC ${target_to_bind}) - endif() + pybind11_add_module(${name} MODULE ${pybind_src_files} "NO_EXTRAS") # NO EXTRA recquired for pip install + target_include_directories(${name} PUBLIC "python_binding") + target_link_libraries(${name} PUBLIC ${target_to_bind}) endfunction() diff --git a/include/aidge/aidge.hpp b/include/aidge/aidge.hpp index ff6601c487ea97294019a12ba899d251b08077e7..cfda3ac7fa024f8cf80b4589d978b9b5bff5b4f0 100644 --- a/include/aidge/aidge.hpp +++ b/include/aidge/aidge.hpp @@ -34,11 +34,13 @@ #include "aidge/operator/FC.hpp" #include "aidge/operator/GenericOperator.hpp" #include "aidge/operator/Matmul.hpp" -#include "aidge/operator/MetaOperator.hpp" +#include "aidge/operator/MaxPooling.hpp" +//#include "aidge/operator/MetaOperator.hpp" #include "aidge/operator/Operator.hpp" #include "aidge/operator/Producer.hpp" #include "aidge/operator/ReLU.hpp" #include "aidge/operator/Softmax.hpp" +#include "aidge/operator/Scaling.hpp" #include "aidge/scheduler/Scheduler.hpp" #include "aidge/utils/CParameter.hpp" #include "aidge/utils/Parameter.hpp" diff --git a/include/aidge/graph/Node.hpp b/include/aidge/graph/Node.hpp index 11def52dbab30159e9e882fb19d16f1549aa3887..340a8318cbd0d59b7710bce7d46b7acd1670dd5b 100644 --- a/include/aidge/graph/Node.hpp +++ b/include/aidge/graph/Node.hpp @@ -303,7 +303,7 @@ public: * @param inId Input index. * @return std::shared_ptr<Node>& */ - inline NodePtr &getParents(const IOIndex_t inId) { + inline NodePtr &getParent(const IOIndex_t inId) { assert(inId != gk_IODefaultIndex); return mParents.at(inId); } diff --git a/include/aidge/hook/execTime.hpp b/include/aidge/hook/execTime.hpp new file mode 100644 index 0000000000000000000000000000000000000000..212fef58696be702e89c8ad973dcc0dd0fc389ae --- /dev/null +++ b/include/aidge/hook/execTime.hpp @@ -0,0 +1,59 @@ +/** + * \file execTime.hpp + * \brief execTime structure + * \version file 1.0.0 + * \date Creation 27 June 2023 + * \date 27 June 2023 + * \par ChangeLog + * \par + * v1.0.0, 27 June 2023<br> + * - Initial version. + * \author mn271187, ik243221 + * \copyright + * Copyright (c) 2023 CEA, LIST, Embedded Artificial Intelligence Laboratory. All + * rights reserved. + */ + +#ifndef execTime_H_ +#define execTime_H_ + +#include "aidge/operator/Operator.hpp" +#include "aidge/hook/hook.hpp" +#include <memory> +#include <chrono> +#include <vector> + +namespace Aidge { + +class ExecTime : public Hook { +private: + std::vector<std::chrono::high_resolution_clock::time_point> registeredTimes = std::vector<std::chrono::high_resolution_clock::time_point>(); +public: + ExecTime(const std::shared_ptr<Operator> op) : Hook(op) {} + ~ExecTime() = default; + + void call() override final { + registeredTimes.push_back(std::chrono::high_resolution_clock::now()); + } + + static std::shared_ptr<ExecTime> create(const std::shared_ptr<Operator> op) + { + return std::make_shared<ExecTime>(op); + } + + std::vector<std::chrono::high_resolution_clock::time_point> getTimes() { + return registeredTimes; + } + + std::chrono::high_resolution_clock::time_point getTime(size_t idx) { + return registeredTimes[idx]; + } + +}; + +namespace { + static Registrar<Hook> registrarHook_ExecTime({"execution_time"}, Aidge::ExecTime::create); +} +} + +#endif /* execTime_H_ */ \ No newline at end of file diff --git a/include/aidge/hook/hook.hpp b/include/aidge/hook/hook.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0448659b937c3498f57cae9935196ef2f38ecf6d --- /dev/null +++ b/include/aidge/hook/hook.hpp @@ -0,0 +1,41 @@ +/** + * \file Hook.hpp + * \brief Hook structure + * \version file 1.0.0 + * \date Creation 27 June 2023 + * \date 27 June 2023 + * \par ChangeLog + * \par + * v1.0.0, 27 June 2023<br> + * - Initial version. + * \author mn271187, ik243221 + * \copyright + * Copyright (c) 2023 CEA, LIST, Embedded Artificial Intelligence Laboratory. All + * rights reserved. + */ + +#ifndef Hook_H_ +#define Hook_H_ + +#include "aidge/utils/Parameter.hpp" +#include "aidge/utils/Registrar.hpp" +#include <memory> + +namespace Aidge { + +class Operator; +class Hook : public Registrable<Hook, std::tuple<std::string>, std::shared_ptr<Hook>(const std::shared_ptr<Operator>)> { +//class Hook : public Registrable<Hook, std::tuple<std::string>, std::shared_ptr<Hook>(const std::shared_ptr<Operator>)>{ +protected: + const std::shared_ptr<Operator> mOperator; + +public: + Hook(std::shared_ptr<Operator> op) : mOperator(op) {} + virtual ~Hook(); + + virtual void call() = 0; + +}; +} + +#endif /* Hook_H_ */ \ No newline at end of file diff --git a/include/aidge/hook/outputRange.hpp b/include/aidge/hook/outputRange.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a2da2a997d594c0ef78fb7c31f33b32c3495c4eb --- /dev/null +++ b/include/aidge/hook/outputRange.hpp @@ -0,0 +1,74 @@ +/** + * \file execTime.hpp + * \brief execTime structure + * \version file 1.0.0 + * \date Creation 27 June 2023 + * \date 27 June 2023 + * \par ChangeLog + * \par + * v1.0.0, 27 June 2023<br> + * - Initial version. + * \author ik243221 + * \copyright + * Copyright (c) 2023 CEA, LIST, Embedded Artificial Intelligence Laboratory. All + * rights reserved. + */ + +#ifndef AIDGE_CORE_HOOK_OUTPUTRANGE_H_ +#define AIDGE_CORE_HOOK_OUTPUTRANGE_H_ + +#include "aidge/operator/Operator.hpp" +#include "aidge/hook/hook.hpp" +#include <memory> +#include <chrono> +#include <vector> +#include <cmath> +namespace Aidge { + +class OutputRange : public Hook { +private: + std::vector<float> registeredOutputs = std::vector<float>(); +public: + OutputRange(const std::shared_ptr<Operator> op) : Hook(op) {} + ~OutputRange() = default; + + void call() override final { + //std::cout << "call() outputRange hook " << std::endl; + //this assumes there is only 1 output possible + std::shared_ptr<Tensor> tensor = mOperator->getOutput(0); + //tensor->print(); + //std::cout << "call() outputRange hook : tensor printed" << std::endl; + float max_value = 0.; + float * casted_tensor = static_cast<float *>(tensor->getImpl()->rawPtr()); + //find the absolute max value in the tensor, save it to registered outputs + for(std::size_t i = 0; i < tensor->size(); ++i) { + //std::cout << "call() outputRange hook : casted_tensor[i] = " << casted_tensor[i] << std::endl; + if(std::abs(casted_tensor[i]) > max_value){ + max_value = std::abs(casted_tensor[i]); + } + } + //std::cout << "call() outputRange hook : max_value = " << max_value << std::endl; + registeredOutputs.push_back(max_value); + } + + static std::shared_ptr<OutputRange> create(const std::shared_ptr<Operator> op) + { + return std::make_shared<OutputRange>(op); + } + + std::vector<float> getOutputs() { + return registeredOutputs; + } + + float getOutput(size_t idx) { + return registeredOutputs[idx]; + } + +}; + +namespace { + static Registrar<Hook> registrarHook_OutputRange({"output_range"}, Aidge::OutputRange::create); +} +} + +#endif /* outputRange_H_ */ \ No newline at end of file diff --git a/include/aidge/operator/MaxPooling.hpp b/include/aidge/operator/MaxPooling.hpp new file mode 100644 index 0000000000000000000000000000000000000000..073243e801c6e1297129424b0c93b1a7c4f112f3 --- /dev/null +++ b/include/aidge/operator/MaxPooling.hpp @@ -0,0 +1,174 @@ +/******************************************************************************** + * 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_MAXPOOLING_H_ +#define AIDGE_CORE_OPERATOR_MAXPOOLING_H_ + +#include <array> +#include <numeric> +#include <vector> +#include <cmath> + +#include "aidge/data/Tensor.hpp" +#include "aidge/graph/Node.hpp" +#include "aidge/operator/Operator.hpp" +#include "aidge/operator/Producer.hpp" +#include "aidge/utils/Parameter.hpp" +#include "aidge/utils/Registrar.hpp" +#include "aidge/utils/Types.h" + +namespace Aidge { +enum class MaxPoolingParam { StrideDims, KernelDims, PaddingDims }; + +template <DimIdx_t DIM> +class MaxPooling_Op : public Operator, + public Registrable<MaxPooling_Op<DIM>, std::string, std::unique_ptr<OperatorImpl>(const MaxPooling_Op<DIM> &)>, + public Parameterizable<MaxPoolingParam, + std::array<DimSize_t, DIM>, + std::array<DimSize_t, DIM>, + std::array<DimSize_t, (DIM<<1) >> { +private: + // FIXME: change accessibility + std::shared_ptr<Tensor> mInput = std::make_shared<Tensor>(); + const std::shared_ptr<Tensor> mOutput = std::make_shared<Tensor>(); + +public: + static constexpr const char *Type = "MaxPooling"; + + MaxPooling_Op() = delete; + + using Parameterizable_ = Parameterizable<MaxPoolingParam, + std::array<DimSize_t, DIM>, + std::array<DimSize_t, DIM>, + std::array<DimSize_t, (DIM<<1)> >; + template <MaxPoolingParam e> + using param = typename Parameterizable_::template param<e>; + + constexpr MaxPooling_Op(const std::array<DimSize_t, DIM> &kernel_dims, + const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1), + const std::array<DimSize_t, (DIM<<1)> &padding_dims = create_array<DimSize_t,(DIM<<1)>(0)) + : Operator(Type), + Parameterizable_(param<MaxPoolingParam::StrideDims>(stride_dims), + param<MaxPoolingParam::KernelDims>(kernel_dims), + param<MaxPoolingParam::PaddingDims>(padding_dims)), + mOutput(std::make_shared<Tensor>()) { + setDatatype(DataType::Float32); + } + + constexpr void associateInput(const IOIndex_t inputIdx, std::shared_ptr<Data> data) override final { + assert(inputIdx < 1 && "operators supports only 3 inputs"); + (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); + } + + constexpr void computeOutputDims() override final { + if (!mInput->empty()) { + std::array<DimSize_t, DIM + 2> outputDims = {}; + + for (std::size_t dim = 0; dim < this->template get<MaxPoolingParam::KernelDims>().size() ; ++dim) { + outputDims[dim+2] = 1 + static_cast<DimSize_t>( + std::floor(static_cast<float>(mInput->dims()[dim+2] - + this->template get<MaxPoolingParam::KernelDims>()[dim] + + this->template get<MaxPoolingParam::PaddingDims>()[dim] + + this->template get<MaxPoolingParam::PaddingDims>()[dim+DIM]) / + static_cast<float>(this->template get<MaxPoolingParam::StrideDims>()[dim]))); + } + outputDims[1] = mInput->dims()[1]; + outputDims[0] = mInput->dims()[0]; + mOutput->resize(outputDims); + } + } + + bool outputDimsForwarded() const override final { return !(mOutput->empty()); } + + + inline Tensor& input(const IOIndex_t inputIdx) const override final { + assert(inputIdx == 0 && "operators supports only 1 inputs"); + (void) inputIdx; // avoid unused warning + return *(mInput.get()); + } + inline Tensor& output(const IOIndex_t /*outputIdx*/) const override final { return *(mOutput.get()); } + + + inline std::shared_ptr<Tensor> getInput(const IOIndex_t inputIdx) const override final { + assert(inputIdx == 0 && "MaxPooling Operators supports only 1 inputs"); + (void) inputIdx; // avoid unused warning + return mInput; + } + inline std::shared_ptr<Tensor> getOutput(const IOIndex_t outputIdx) const override final { + assert(outputIdx == 0 && "MaxPooling Operators has only 1 outputs"); + (void) outputIdx; // avoid unused warning + return mOutput; + } + + + std::shared_ptr<Data> getRawInput(const IOIndex_t inputIdx) const override final { + assert(inputIdx == 0 && "operators supports only 1 inputs"); + (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>(mOutput); + } + + + void setBackend(const std::string &name) { + mImpl = Registrar<MaxPooling_Op<DIM>>::create(name)(*this); + mOutput->setBackend(name); + + // FIXME: temporary workaround + mInput->setBackend(name); + } + + void setDatatype(const DataType &datatype) { + mOutput->setDatatype(datatype); + + // FIXME: temporary workaround + mInput->setDatatype(datatype); + } + + 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; } +}; + +template <std::array<DimSize_t, 1>::size_type DIM> +inline std::shared_ptr<Node> MaxPooling(const std::array<DimSize_t, DIM> &kernel_dims, + const std::string& name = "", + const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1), + const std::array<DimSize_t, (DIM<<1)> &padding_dims = create_array<DimSize_t,(DIM<<1)>(0)) { + // FIXME: properly handle default w&b initialization in every cases + static_assert(DIM<=MaxDim,"Too many kernel dimensions required by MaxPooling, not supported"); + auto avgPool = std::make_shared<Node>(std::make_shared<MaxPooling_Op<static_cast<DimIdx_t>(DIM)>>(kernel_dims, stride_dims, padding_dims), name); + return avgPool; +} + +template <DimSize_t DIM> +inline std::shared_ptr<Node> MaxPooling( + DimSize_t const (&kernel_dims)[DIM], + const std::string& name = "", + const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1), + const std::array<DimSize_t, (DIM<<1)> &padding_dims = create_array<DimSize_t,(DIM<<1)>(0)) { + static_assert(DIM<=MaxDim,"Too many kernel dimensions required by MaxPooling, not supported"); + return MaxPooling(to_array(kernel_dims), name, stride_dims, padding_dims); +} +} // namespace Aidge + +namespace { +template <> +const char *const EnumStrings<Aidge::MaxPoolingParam>::data[] = {"StrideDims", "KernelDims", "PaddingDims"}; +} + +#endif /* AIDGE_CORE_OPERATOR_MAXPOOLING_H_ */ diff --git a/include/aidge/operator/Operator.hpp b/include/aidge/operator/Operator.hpp index 36f846ddae329be28b8e51e2bff1580a509562e1..122a42a42f38309aa1cd1661324fcc6f5c2d3fcc 100644 --- a/include/aidge/operator/Operator.hpp +++ b/include/aidge/operator/Operator.hpp @@ -20,12 +20,14 @@ #include "aidge/data/Data.hpp" #include "aidge/data/Tensor.hpp" #include "aidge/utils/Types.h" +#include "aidge/hook/hook.hpp" namespace Aidge { class Operator : public std::enable_shared_from_this<Operator> { protected: std::unique_ptr<OperatorImpl> mImpl; // implementation of the operator + std::map<std::string, std::shared_ptr<Hook>> mHooks; private: std::string mType; @@ -48,6 +50,15 @@ public: virtual std::shared_ptr<Tensor> getOutput(const IOIndex_t outputIdx) const = 0; virtual Tensor& output(const IOIndex_t /*outputIdx*/) const = 0; + std::shared_ptr<Hook> getHook(std::string hookName) { + return mHooks[hookName]; + } + void addHook(std::string hookName) { + mHooks.insert(std::pair<std::string, std::shared_ptr<Hook>>(hookName,Registrar<Hook>::create({hookName})(shared_from_this()))); + } + + void runHooks() const; + /////////////////////////////////////////////////////// // IMPLEMENTATION /////////////////////////////////////////////////////// diff --git a/include/aidge/operator/Scaling.hpp b/include/aidge/operator/Scaling.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e158ecd7567eb683558d9e09a6cf03e5cc35ce42 --- /dev/null +++ b/include/aidge/operator/Scaling.hpp @@ -0,0 +1,140 @@ +/******************************************************************************** + * 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_Scaling_H__ +#define __AIDGE_CORE_OPERATOR_Scaling_H__ + +#include <vector> +#include <memory> + + + +#include "aidge/utils/Parameter.hpp" +#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 { +enum class ScalingParam { + scalingFactor +}; + +class Scaling_Op : public Operator, + public Registrable<Scaling_Op, std::string, std::unique_ptr<OperatorImpl>(const Scaling_Op&)>, + public Parameterizable<ScalingParam, float> { +public: + // FIXME: change accessibility + std::shared_ptr<Tensor> mInput = std::make_shared<Tensor>(); + const std::shared_ptr<Tensor> mOutput = std::make_shared<Tensor>(); + +public: + static constexpr const char* Type = "Scaling"; + + Scaling_Op() = delete; + + using Parameterizable_ = Parameterizable<ScalingParam, float>; + template <ScalingParam e> using param = typename Parameterizable_::template param<e>; + + Scaling_Op(float scalingFactor) + : Operator(Type), + Parameterizable_( + param<ScalingParam::scalingFactor>(scalingFactor)) + { + setDatatype(DataType::Float32); + } + + void associateInput(const IOIndex_t inputIdx, std::shared_ptr<Data> data) override final { + assert(inputIdx == 0 && "operator supports only 1 input"); + assert(strcmp(data->type(), Tensor::Type)==0 && "input data must be of Tensor type"); + (void) inputIdx; //avoid unused warning + mInput = std::dynamic_pointer_cast<Tensor>(data); + } + + void computeOutputDims() override final { + if (!mInput->empty()) + mOutput->resize(mInput->dims()); + } + + bool outputDimsForwarded() const override final { + return !(mOutput->empty()); + } + + + inline Tensor& input(const IOIndex_t inputIdx) const override final { + assert((inputIdx == 0) && "Scaling Operator has only 1 input"); + (void) inputIdx; // avoid unused warning + return *(mInput.get()); + } + inline Tensor& output(const IOIndex_t outputIdx) const override final { + assert((outputIdx == 0) && "Scaling Operator has only 1 output"); + (void) outputIdx; // avoid unused warning + return *(mOutput.get()); + } + + + inline std::shared_ptr<Tensor> getInput(const IOIndex_t inputIdx) const override final { + assert((inputIdx == 0) && "Scaling 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) && "Scaling Operator has only 1 output"); + (void) outputIdx; // avoid unused warning + return mOutput; + } + + + 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 mOutput; + } + + + void setBackend(const std::string& name) { + mImpl = Registrar<Scaling_Op>::create(name)(*this); + mOutput->setBackend(name); + // FIXME: temporary workaround + mInput->setBackend(name); + } + void setDatatype(const DataType& datatype) { + mOutput->setDatatype(datatype); + + // FIXME: temporary workaround + mInput->setDatatype(datatype); + } + + 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; } +}; + +inline std::shared_ptr<Node> Scaling(float scalingFactor = 1.0f, const std::string& name = "") { + return std::make_shared<Node>(std::make_shared<Scaling_Op>(scalingFactor), name); +} +} + +namespace { +template <> +const char* const EnumStrings<Aidge::ScalingParam>::data[] + = {"scalingFactor"}; +} + +#endif /* __AIDGE_CORE_OPERATOR_RELU_H__ */ diff --git a/python_binding/graph/pybind_Node.cpp b/python_binding/graph/pybind_Node.cpp index 62b86982053d82bef6e0fd80e490632b95b968e5..e3666d247324fc419570611f41bbe67c7c68cc4e 100644 --- a/python_binding/graph/pybind_Node.cpp +++ b/python_binding/graph/pybind_Node.cpp @@ -136,6 +136,16 @@ void init_Node(py::module& m) { :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")); } } // namespace Aidge diff --git a/python_binding/operator/pybind_MaxPooling.cpp b/python_binding/operator/pybind_MaxPooling.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9bd951c446e080ff27b099527ac9bbc350646140 --- /dev/null +++ b/python_binding/operator/pybind_MaxPooling.cpp @@ -0,0 +1,89 @@ +/******************************************************************************** + * 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 + * + ********************************************************************************/ +#ifdef PYBIND +#include <pybind11/pybind11.h> +#include <pybind11/stl.h> + +#include <string> +#include <vector> +#include <array> + +#include "aidge/utils/Parameter.hpp" +#include "aidge/backend/OperatorImpl.hpp" +#include "aidge/operator/MaxPooling.hpp" +#include "aidge/operator/Operator.hpp" +#include "aidge/utils/Types.h" +#include "aidge/data/Tensor.hpp" + +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>( + m, ("MaxPoolingOp" + std::to_string(DIM) + "D").c_str(), + py::multiple_inheritance()) + .def(py::init<const std::array<DimSize_t, DIM> &, + const std::array<DimSize_t, DIM> &, + const std::array<DimSize_t, (DIM<<1)> &>(), + py::arg("kernel_dims"), + py::arg("stride_dims"), + py::arg("padding_dims")); + + m.def(("MaxPooling" + std::to_string(DIM) + "D").c_str(), [](const std::vector<DimSize_t>& kernel_dims, + const std::string& name, + const std::vector<DimSize_t> &stride_dims, + const std::vector<DimSize_t> &padding_dims) { + // Lambda function wrapper because PyBind fails to convert const array. + // So we use a vector that we convert in this function to a const DimeSize_t [DIM] array. + if (kernel_dims.size() != DIM) { + throw std::runtime_error("kernel_dims size [" + std::to_string(kernel_dims.size()) + "] does not match DIM [" + std::to_string(DIM) +"]"); + } + if (stride_dims.size() != DIM) { + throw std::runtime_error("stride_dims size [" + std::to_string(stride_dims.size()) + "] does not match DIM [" + std::to_string(DIM) +"]"); + } + if (padding_dims.size() != (DIM<<1)) { + throw std::runtime_error("padding_dims size [" + std::to_string(padding_dims.size()) + "] does not match DIM [" + std::to_string(DIM<<1) +"]"); + } + DimSize_t tmp_kernel_dims_array[DIM]; + for (size_t i = 0; i < DIM; ++i) { + tmp_kernel_dims_array[i] = kernel_dims[i]; + } + DimSize_t tmp_stride_dims_array[DIM]; + for (size_t i = 0; i < DIM; ++i) { + tmp_stride_dims_array[i] = stride_dims[i]; + } + DimSize_t tmp_padding_dims_array[DIM<<1]; + for (size_t i = 0; i < (DIM<<1); ++i) { + tmp_padding_dims_array[i] = padding_dims[i]; + } + const DimSize_t (&kernel_dims_array)[DIM] = tmp_kernel_dims_array; + const DimSize_t (&stride_dims_array)[DIM] = tmp_stride_dims_array; + const DimSize_t (&padding_dims_array)[DIM<<1] = tmp_padding_dims_array; + return MaxPooling<DIM>(to_array(kernel_dims_array), name, to_array(stride_dims_array), to_array(padding_dims_array)); + }, py::arg("kernel_dims"), + py::arg("name") = "", + py::arg("stride_dims") = std::vector<DimSize_t>(DIM,1), + py::arg("padding_dims") = std::vector<DimSize_t>(DIM<<1,0)); + +} + + +void init_MaxPooling(py::module &m) { + declare_MaxPoolingOp<1>(m); + declare_MaxPoolingOp<2>(m); + declare_MaxPoolingOp<3>(m); + + // FIXME: + // m.def("MaxPooling1D", static_cast<NodeAPI(*)(const char*, int, int, int const + // (&)[1])>(&MaxPooling)); +} +} // namespace Aidge +#endif \ No newline at end of file diff --git a/python_binding/pybind_core.cpp b/python_binding/pybind_core.cpp index b861f881c684a2fbe800ab672299871cfc89d7ac..78418d51a5c410cb56bb8421fd7f3dc6ec6d32db 100644 --- a/python_binding/pybind_core.cpp +++ b/python_binding/pybind_core.cpp @@ -29,6 +29,7 @@ void init_FC(py::module&); void init_GenericOperator(py::module&); void init_LeakyReLU(py::module&); void init_Matmul(py::module&); +void init_MaxPooling(py::module&); void init_Producer(py::module&); void init_ReLU(py::module&); void init_Softmax(py::module&); @@ -75,6 +76,7 @@ void init_Aidge(py::module& m){ init_GenericOperator(m); init_LeakyReLU(m); init_Matmul(m); + init_MaxPooling(m); init_ReLU(m); init_Softmax(m); diff --git a/src/graph/GraphView.cpp b/src/graph/GraphView.cpp index a0641032281c6bedb4459a0d08da1193d6375129..7cb4e1dcf33b71bec87ea883aceb8c8a3c49a5ba 100644 --- a/src/graph/GraphView.cpp +++ b/src/graph/GraphView.cpp @@ -326,7 +326,7 @@ void Aidge::GraphView::add(std::shared_ptr<Node> node, bool includeLearnablePara // add learnable parameters to the graph if (includeLearnableParam) { for (IOIndex_t i = node->nbDataInputs(); i < node->nbInputs(); ++i) { - std::shared_ptr<Node> parentNode = node->getParents(static_cast<IOIndex_t>(i)); + std::shared_ptr<Node> parentNode = node->getParent(static_cast<IOIndex_t>(i)); if (parentNode) { parentNode->addView(shared_from_this()); mNodes.insert(parentNode); diff --git a/src/graph/Node.cpp b/src/graph/Node.cpp index 5fcc0e1139d8ccd9368eaba90231fb12370e761e..abf572831d8f0b5c2c5eb836ea46e05b8114da55 100644 --- a/src/graph/Node.cpp +++ b/src/graph/Node.cpp @@ -226,7 +226,7 @@ void Aidge::Node::addChild(std::shared_ptr<GraphView> otherView, const IOIndex_t } void Aidge::Node::addParent(const std::shared_ptr<Node> other_node, const IOIndex_t inId) { - if (getParents(inId) != nullptr) { + if (getParent(inId) != nullptr) { printf("Warning, you're replacing a Parent.\n"); } assert((inId != gk_IODefaultIndex) && (inId < nbInputs()) && "Input index out of bound."); diff --git a/src/operator/Operator.cpp b/src/operator/Operator.cpp index b3896b12143488275b2a064819595c380da62844..09a17a428e1de91c0318f710e6f097573cf529a6 100644 --- a/src/operator/Operator.cpp +++ b/src/operator/Operator.cpp @@ -42,6 +42,14 @@ void Aidge::Operator::updateConsummerProducer(){ mImpl->updateConsummerProducer(); } -void Aidge::Operator::forward() { mImpl->forward(); } +void Aidge::Operator::runHooks() const { + for (auto& hook : mHooks) { + hook.second->call(); + } +} +void Aidge::Operator::forward() { + mImpl->forward(); + runHooks(); +} void Aidge::Operator::backward() { mImpl->backward(); } diff --git a/src/recipies/FuseMulAdd.cpp b/src/recipies/FuseMulAdd.cpp index dc565bf0acc7747d79ec12df973a82d86fc79503..561d25776a28f1aad8f8c943711887ec6661a10c 100644 --- a/src/recipies/FuseMulAdd.cpp +++ b/src/recipies/FuseMulAdd.cpp @@ -59,12 +59,12 @@ void Aidge::fuseMulAdd(std::set<std::shared_ptr<Node>> nodes){ // Step 2 : Branch existing producers & create the others // link weights & bias - if (matmul->getParents(1)==nullptr) { - matmul->getParents(0)->addChild(fc, 0, 1); + if (matmul->getParent(1)==nullptr) { + matmul->getParent(0)->addChild(fc, 0, 1); } else { - if (matmul->getParents(0)!=nullptr) - matmul->getParents(0)->addChild(fc, 0, 0); - matmul->getParents(1)->addChild(fc, 0, 1); + if (matmul->getParent(0)!=nullptr) + matmul->getParent(0)->addChild(fc, 0, 0); + matmul->getParent(1)->addChild(fc, 0, 1); } (producer_add_bias.first)->addChild(fc,0,2);