Skip to content
Snippets Groups Projects
Commit bed0f107 authored by Thibault Allenet's avatar Thibault Allenet
Browse files

Merge branch 'main' into dataloader

parents 3e92caae c8c16f2e
No related branches found
No related tags found
No related merge requests found
Showing
with 545 additions and 112 deletions
...@@ -9,6 +9,14 @@ variables: ...@@ -9,6 +9,14 @@ variables:
GIT_SSL_NO_VERIFY: 1 GIT_SSL_NO_VERIFY: 1
DEBIAN_FRONTEND: noninteractive DEBIAN_FRONTEND: noninteractive
# See https://docs.gitlab.com/ee/ci/yaml/workflow.html#switch-between-branch-pipelines-and-merge-request-pipelines
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
when: never
- if: $CI_COMMIT_BRANCH
default: default:
image: nvidia/cuda:12.2.0-devel-ubuntu22.04 image: nvidia/cuda:12.2.0-devel-ubuntu22.04
before_script: before_script:
......
...@@ -12,10 +12,71 @@ build:ubuntu_cpp: ...@@ -12,10 +12,71 @@ build:ubuntu_cpp:
- make -j4 all install - make -j4 all install
artifacts: artifacts:
expire_in: 1 week
paths: paths:
- build_cpp/ - build_cpp/
- install_cpp/ - install_cpp/
build:ubuntu_cpp_g++10:
stage: build
needs: []
tags:
- docker
script:
- apt install -y g++-10
- mkdir -p build_cpp
- mkdir -p install_cpp
- cd build_cpp
- export CXX=/usr/bin/g++-10
- cmake -DCMAKE_INSTALL_PREFIX:PATH=../install_cpp -DCMAKE_BUILD_TYPE=Debug -DWERROR=ON -DCOVERAGE=ON ..
- make -j4 all install
build:ubuntu_cpp_g++12:
stage: build
needs: []
tags:
- docker
script:
- apt install -y g++-12
- mkdir -p build_cpp
- mkdir -p install_cpp
- cd build_cpp
- export CXX=/usr/bin/g++-12
- cmake -DCMAKE_INSTALL_PREFIX:PATH=../install_cpp -DCMAKE_BUILD_TYPE=Debug -DWERROR=ON -DCOVERAGE=ON ..
- make -j4 all install
build:ubuntu_cpp_clang12:
stage: build
needs: []
tags:
- docker
script:
- apt install -y clang-12
- mkdir -p build_cpp
- mkdir -p install_cpp
- cd build_cpp
- export CXX=/usr/bin/clang++-12
- cmake -DCMAKE_INSTALL_PREFIX:PATH=../install_cpp -DCMAKE_BUILD_TYPE=Debug -DWERROR=ON -DCOVERAGE=ON ..
- make -j4 all install
build:ubuntu_cpp_clang15:
stage: build
needs: []
tags:
- docker
script:
- apt install -y clang-15
- mkdir -p build_cpp
- mkdir -p install_cpp
- cd build_cpp
- export CXX=/usr/bin/clang++-15
- cmake -DCMAKE_INSTALL_PREFIX:PATH=../install_cpp -DCMAKE_BUILD_TYPE=Debug -DWERROR=ON -DCOVERAGE=ON ..
- make -j4 all install
build:ubuntu_python: build:ubuntu_python:
stage: build stage: build
needs: [] needs: []
...@@ -26,9 +87,11 @@ build:ubuntu_python: ...@@ -26,9 +87,11 @@ build:ubuntu_python:
- python3 -m pip install virtualenv - python3 -m pip install virtualenv
- virtualenv venv - virtualenv venv
- source venv/bin/activate - source venv/bin/activate
- export AIDGE_INSTALL=`pwd`/install # Numpy dependancy for unit test
- python3 -m pip install -r requirements.txt
- python3 -m pip install . - python3 -m pip install .
artifacts: artifacts:
expire_in: 1 week
paths: paths:
- venv/ - venv/
...@@ -57,6 +120,35 @@ build:windows_cpp: ...@@ -57,6 +120,35 @@ build:windows_cpp:
- cmake --install . --config Debug - cmake --install . --config Debug
artifacts: artifacts:
expire_in: 1 week
paths: paths:
- build_cpp/ - build_cpp/
- install_cpp/ - install_cpp/
build:windows_python:
stage: build
needs: []
tags:
- windows
image: buildtools
before_script:
# Install Chocolatey
- Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
# Install dependencies
- choco install cmake.install --installargs '"ADD_CMAKE_TO_PATH=System"' -Y
- choco install git -Y
- choco install python -Y
# Update PATH
- $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
script:
- python -m pip install virtualenv
- virtualenv venv
- venv\Scripts\Activate.ps1
# Numpy dependancy for unit test
- python -m pip install -r requirements.txt
- python -m pip install .
artifacts:
expire_in: 1 week
paths:
- venv/
...@@ -24,8 +24,10 @@ coverage:ubuntu_python: ...@@ -24,8 +24,10 @@ coverage:ubuntu_python:
script: script:
- source venv/bin/activate - source venv/bin/activate
- python3 -m pip install numpy coverage - python3 -m pip install numpy coverage
- cd aidge_core - cd ${CI_PROJECT_NAME}
- python3 -m coverage run --source=. -m unittest discover -s unit_tests/ -v -b # Retrieve the installation path of the module, since it is installed with pip.
- export MODULE_LOCATION=`python -c "import ${CI_PROJECT_NAME} as _; print(_.__path__[0])"`
- python3 -m coverage run --source=$MODULE_LOCATION -m unittest discover -s unit_tests/ -v -b
- python3 -m coverage report - python3 -m coverage report
- python3 -m coverage xml - python3 -m coverage xml
coverage: '/(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/' coverage: '/(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/'
...@@ -33,4 +35,4 @@ coverage:ubuntu_python: ...@@ -33,4 +35,4 @@ coverage:ubuntu_python:
reports: reports:
coverage_report: coverage_report:
coverage_format: cobertura coverage_format: cobertura
path: aidge_core/coverage.xml path: ${CI_PROJECT_NAME}/coverage.xml
...@@ -26,8 +26,8 @@ static_analysis:python: ...@@ -26,8 +26,8 @@ static_analysis:python:
script: script:
- pip install pylint - pip install pylint
- pip install pylint-gitlab - pip install pylint-gitlab
- pylint --rcfile=.pylintrc --exit-zero --output-format=pylint_gitlab.GitlabCodeClimateReporter aidge_core/ > codeclimate.json - pylint --rcfile=.pylintrc --exit-zero --output-format=pylint_gitlab.GitlabCodeClimateReporter ${CI_PROJECT_NAME}/ > codeclimate.json
- pylint --rcfile=.pylintrc --exit-zero --output-format=pylint_gitlab.GitlabPagesHtmlReporter aidge_core/ > pylint.html - pylint --rcfile=.pylintrc --exit-zero --output-format=pylint_gitlab.GitlabPagesHtmlReporter ${CI_PROJECT_NAME}/ > pylint.html
- mkdir -p public/python/$CI_COMMIT_REF_NAME - mkdir -p public/python/$CI_COMMIT_REF_NAME
- mv pylint.html public/python/$CI_COMMIT_REF_NAME/ - mv pylint.html public/python/$CI_COMMIT_REF_NAME/
artifacts: artifacts:
......
...@@ -17,14 +17,14 @@ test:ubuntu_python: ...@@ -17,14 +17,14 @@ test:ubuntu_python:
- docker - docker
script: script:
- source venv/bin/activate - source venv/bin/activate
- cd aidge_core - cd ${CI_PROJECT_NAME}
- python3 -m pip install unittest-xml-reporting - python3 -m pip install unittest-xml-reporting
- python3 -m pip list - python3 -m pip list
# Run on discovery all tests located in core/unit_tests/python # Run on discovery all tests located in core/unit_tests/python
- python3 -m xmlrunner discover -s unit_tests/ -v -b --output-file xmlrunner-results.xml - python3 -m xmlrunner discover -s unit_tests/ -v -b --output-file xmlrunner-results.xml
artifacts: artifacts:
reports: reports:
junit: aidge_core/xmlrunner-results.xml junit: ${CI_PROJECT_NAME}/xmlrunner-results.xml
test:windows_cpp: test:windows_cpp:
stage: test stage: test
...@@ -37,6 +37,7 @@ test:windows_cpp: ...@@ -37,6 +37,7 @@ test:windows_cpp:
- Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) - Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
# Install dependencies # Install dependencies
- choco install cmake.install --installargs '"ADD_CMAKE_TO_PATH=System"' -Y - choco install cmake.install --installargs '"ADD_CMAKE_TO_PATH=System"' -Y
- choco install python -Y
# Update PATH # Update PATH
- $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") - $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
script: script:
......
...@@ -6,7 +6,7 @@ file(READ "${CMAKE_SOURCE_DIR}/project_name.txt" project) ...@@ -6,7 +6,7 @@ file(READ "${CMAKE_SOURCE_DIR}/project_name.txt" project)
message(STATUS "Project name: ${project}") message(STATUS "Project name: ${project}")
message(STATUS "Project version: ${version}") message(STATUS "Project version: ${version}")
# Note : project name is {project} and python module name is also {project} # Note : project name is {project} and python module name is also {project}
set(module_name _${project}) # target name set(module_name _${project}) # target name
...@@ -52,12 +52,12 @@ target_include_directories(${module_name} ...@@ -52,12 +52,12 @@ target_include_directories(${module_name}
) )
# PYTHON BINDING # PYTHON BINDING
generate_python_binding(${project} ${module_name})
if (PYBIND) if (PYBIND)
generate_python_binding(${project} ${module_name})
# Handles Python + pybind11 headers dependencies # Handles Python + pybind11 headers dependencies
target_link_libraries(${module_name} target_link_libraries(${module_name}
PUBLIC PUBLIC
pybind11::pybind11 pybind11::pybind11
PRIVATE PRIVATE
Python::Python Python::Python
...@@ -66,22 +66,16 @@ endif() ...@@ -66,22 +66,16 @@ endif()
target_compile_features(${module_name} PRIVATE cxx_std_14) target_compile_features(${module_name} PRIVATE cxx_std_14)
# -fvisibility=hidden required by pybind11
if(WERROR) target_compile_options(${module_name} PUBLIC
target_compile_options(${module_name} PRIVATE $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:GNU>>:
-fvisibility=hidden>)
target_compile_options(${module_name} PRIVATE
$<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:GNU>>: $<$<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>) -Wall -Wextra -Wold-style-cast -Winline -pedantic -Werror=narrowing -Wshadow $<$<BOOL:${WERROR}>:-Werror>>)
target_compile_options(${module_name} PRIVATE target_compile_options(${module_name} PRIVATE
$<$<CXX_COMPILER_ID:MSVC>: $<$<CXX_COMPILER_ID:MSVC>:
/W4>) /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>)
target_compile_options(${module_name} PRIVATE
$<$<CXX_COMPILER_ID:MSVC>:
/W4>)
endif()
if(CMAKE_COMPILER_IS_GNUCXX AND COVERAGE) if(CMAKE_COMPILER_IS_GNUCXX AND COVERAGE)
append_coverage_compiler_flags() append_coverage_compiler_flags()
...@@ -107,8 +101,8 @@ install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) ...@@ -107,8 +101,8 @@ install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(EXPORT ${project}-targets install(EXPORT ${project}-targets
FILE "${project}-targets.cmake" FILE "${project}-targets.cmake"
DESTINATION ${INSTALL_CONFIGDIR} DESTINATION ${INSTALL_CONFIGDIR}
# COMPONENT ${module_name} # COMPONENT ${module_name}
) )
#Create a ConfigVersion.cmake file #Create a ConfigVersion.cmake file
include(CMakePackageConfigHelpers) include(CMakePackageConfigHelpers)
...@@ -142,4 +136,4 @@ export(EXPORT ${project}-targets ...@@ -142,4 +136,4 @@ export(EXPORT ${project}-targets
if(TEST) if(TEST)
enable_testing() enable_testing()
add_subdirectory(unit_tests) add_subdirectory(unit_tests)
endif() endif()
\ No newline at end of file
...@@ -6,16 +6,19 @@ You can find here the C++ code of the Core library of Aidge. ...@@ -6,16 +6,19 @@ You can find here the C++ code of the Core library of Aidge.
## Pip installation ## Pip installation
To install aidge_core using pip, make sure to set the desired install path :
``` bash
export AIDGE_INSTALL = '<path_to_aidge>/install'
```
Then run in your python environnement :
To install aidge_core using pip, run the following command in your python environnement :
``` bash ``` bash
pip install . -v pip install . -v
``` ```
**Note:** you can specify a custom install folder by setting an environment variable:
``` bash
export AIDGE_INSTALL='<path_to_aidge>/install'
```
## Standard C++ Compilation ## Standard C++ Compilation
Create two directories ``build`` and ``ìnstall``. Create two directories ``build`` and ``ìnstall``.
......
...@@ -8,3 +8,4 @@ http://www.eclipse.org/legal/epl-2.0. ...@@ -8,3 +8,4 @@ http://www.eclipse.org/legal/epl-2.0.
SPDX-License-Identifier: EPL-2.0 SPDX-License-Identifier: EPL-2.0
""" """
from aidge_core.aidge_core import * # import so generated by PyBind from aidge_core.aidge_core import * # import so generated by PyBind
from aidge_core.export import ExportNode
from .node_export import *
import aidge_core
from abc import ABC, abstractmethod
class ExportNode(ABC):
"""Abstract class to interface node with export generation.
"""
@abstractmethod
def __init__(self, aidge_node: aidge_core.Node) -> None:
"""Create ExportNode and retieve attirubtes from ``aidge_node``:
- name: aidge Node name
- attributes: dictionnary of attributes of the aidge Operator linked to the node, attributes name follow aidge naming convention
- parameters: List of parameters node, order in the list is the same as the one defined by the aidge operator
"""
super().__init__()
self.node = aidge_node
self.operator = aidge_node.get_operator()
self.name = self.node.name()
self.attributes = {} # Attributes are auto fetched from aidge operators
if isinstance(self.operator, aidge_core.Attributes):
for attr_name in self.operator.get_attrs_name():
self.attributes[attr_name] = self.operator.get_attr(attr_name)
# rename is_leaf ?
self.is_last = len(self.node.get_children()) == 0
self.inputs = []
self.outputs = []
self.inputs_dims = []
self.outputs_dims = []
for idx, parent_node in enumerate(self.node.get_parents()):
self.inputs.append(parent_node)
if parent_node is not None:
self.inputs_dims.append(self.operator.input(idx).dims())
else:
self.inputs_dims.append(None)
for idx, child_node in enumerate(self.node.get_children()):
self.outputs.append(child_node)
# Dirty hot fix, change it quickly
self.outputs_dims.append(self.operator.output(0).dims())
@abstractmethod
def export(self, export_folder:str, list_configs:list):
"""Define how to export the node definition.
"""
pass
@abstractmethod
def forward(self, list_actions:list):
"""Define how to generate code to perform a forward pass.
"""
pass
...@@ -30,36 +30,102 @@ class test_operator_binding(unittest.TestCase): ...@@ -30,36 +30,102 @@ class test_operator_binding(unittest.TestCase):
self.assertNotEqual(gop.name(), "") self.assertNotEqual(gop.name(), "")
def test_param_bool(self): def test_param_bool(self):
self.generic_operator.add_parameter("bool", True) self.generic_operator.add_attr("bool", True)
self.assertEqual(self.generic_operator.get_parameter("bool"), True) self.assertEqual(self.generic_operator.has_attr("bool"), True)
self.assertEqual(self.generic_operator.get_attr("bool"), True)
self.assertEqual(self.generic_operator.get_attr_type("bool"), "bool")
self.assertEqual(self.generic_operator.get_attrs_name(), {"bool"})
self.generic_operator.del_attr("bool")
self.assertEqual(self.generic_operator.has_attr("bool"), False)
self.assertEqual(len(self.generic_operator.get_attrs_name()), 0)
def test_param_int(self): def test_param_int(self):
self.generic_operator.add_parameter("int", 1) self.generic_operator.add_attr("int", 1)
self.assertEqual(self.generic_operator.get_parameter("int"), 1) self.assertEqual(self.generic_operator.get_attr("int"), 1)
def test_param_float(self): def test_param_float(self):
self.generic_operator.add_parameter("float", 2.0) self.generic_operator.add_attr("float", 2.0)
self.assertEqual(self.generic_operator.get_parameter("float"), 2.0) self.assertEqual(self.generic_operator.get_attr("float"), 2.0)
def test_param_str(self): def test_param_str(self):
self.generic_operator.add_parameter("str", "value") self.generic_operator.add_attr("str", "value")
self.assertEqual(self.generic_operator.get_parameter("str"), "value") self.assertEqual(self.generic_operator.get_attr("str"), "value")
def test_param_l_int(self): def test_param_l_int(self):
self.generic_operator.add_parameter("l_int", [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]) self.generic_operator.add_attr("l_int", [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15])
self.assertEqual(self.generic_operator.get_parameter("l_int"), [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]) self.assertEqual(self.generic_operator.get_attr("l_int"), [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15])
def test_param_l_bool(self): def test_param_l_bool(self):
self.generic_operator.add_parameter("l_bool", [True, False, False, True]) self.generic_operator.add_attr("l_bool", [True, False, False, True])
self.assertEqual(self.generic_operator.get_parameter("l_bool"), [True, False, False, True]) self.assertEqual(self.generic_operator.get_attr("l_bool"), [True, False, False, True])
def test_param_l_float(self): def test_param_l_float(self):
self.generic_operator.add_parameter("l_float", [2.0, 1.0]) self.generic_operator.add_attr("l_float", [2.0, 1.0])
self.assertEqual(self.generic_operator.get_parameter("l_float"), [2.0, 1.0]) self.assertEqual(self.generic_operator.get_attr("l_float"), [2.0, 1.0])
def test_param_l_str(self): def test_param_l_str(self):
self.generic_operator.add_parameter("l_str", ["ok"]) self.generic_operator.add_attr("l_str", ["ok"])
self.assertEqual(self.generic_operator.get_parameter("l_str"), ["ok"]) self.assertEqual(self.generic_operator.get_attr("l_str"), ["ok"])
def test_dynamicattribute_binding(self):
# Check original C++ attributes are binded
attrs = aidge_core.test_DynamicAttributes_binding()
self.assertEqual(attrs.has_attr("a"), True)
self.assertEqual(attrs.get_attr("a"), 42)
self.assertEqual(attrs.has_attr("b"), True)
self.assertEqual(attrs.get_attr("b"), "test")
self.assertEqual(attrs.has_attr("c"), True)
self.assertEqual(attrs.get_attr("c"), [True, False, True])
self.assertEqual(attrs.get_attrs_name(), {"a", "b", "c"})
self.assertEqual(attrs.has_attr("d"), False)
# Add Python attributes
attrs.add_attr("d", 18.56)
self.assertEqual(attrs.get_attr("d"), 18.56)
self.assertEqual(attrs.has_attr("d"), True)
self.assertEqual(attrs.get_attrs_name(), {"a", "b", "c", "d"})
self.assertEqual(attrs.has_attr("e"), False)
# Check that added Python attribute is accessible in C++
# Return the value of an attribute named "d" of type float64 (double in C++)
self.assertEqual(aidge_core.test_DynamicAttributes_binding_check(attrs), 18.56)
attrs.set_attr("d", 23.89)
self.assertEqual(aidge_core.test_DynamicAttributes_binding_check(attrs), 23.89)
def test_compute_output_dims(self):
in_dims=[25, 25]
input = aidge_core.Producer(in_dims, name="In")
genOp = aidge_core.GenericOperator("genOp", 1, 1, 1, name="genOp")
_ = aidge_core.sequential([input, genOp])
self.assertListEqual(genOp.get_operator().output(0).dims(), [])
genOp.get_operator().set_compute_output_dims(lambda x:x)
genOp.get_operator().compute_output_dims()
self.assertListEqual(genOp.get_operator().output(0).dims(), in_dims)
def test_set_impl(self):
class PythonCustomImpl(aidge_core.OperatorImpl):
"""Dummy implementation to test that C++ call python code
"""
def __init__(self, op: aidge_core.Operator):
aidge_core.OperatorImpl.__init__(self, op) # Recquired to avoid type error !
self.idx = 0
def forward(self):
"""Increment idx attribute on forward.
"""
self.idx += 1
generic_node = aidge_core.GenericOperator("Relu", 1, 1, 1, name="myReLu")
generic_op = generic_node.get_operator()
customImpl = PythonCustomImpl(generic_op)
generic_op.forward() # Do nothing, no implementation set
generic_op.set_impl(customImpl)
generic_op.forward() # Increment idx
self.assertEqual(customImpl.idx, 1)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
\ No newline at end of file
...@@ -11,7 +11,7 @@ SPDX-License-Identifier: EPL-2.0 ...@@ -11,7 +11,7 @@ SPDX-License-Identifier: EPL-2.0
import unittest import unittest
import aidge_core import aidge_core
class test_parameters(unittest.TestCase): class test_attributes(unittest.TestCase):
"""Very basic test to make sure the python APi is not broken. """Very basic test to make sure the python APi is not broken.
Can be remove in later stage of the developpement. Can be remove in later stage of the developpement.
""" """
...@@ -27,21 +27,21 @@ class test_parameters(unittest.TestCase): ...@@ -27,21 +27,21 @@ class test_parameters(unittest.TestCase):
out_channels = 8 out_channels = 8
k_dims = [2, 2] k_dims = [2, 2]
conv_op = aidge_core.Conv2D(in_channels , out_channels, k_dims).get_operator() conv_op = aidge_core.Conv2D(in_channels , out_channels, k_dims).get_operator()
self.assertEqual(conv_op.get("InChannels"), in_channels) self.assertEqual(conv_op.get_attr("InChannels"), in_channels)
self.assertEqual(conv_op.get("OutChannels"), out_channels) self.assertEqual(conv_op.get_attr("OutChannels"), out_channels)
self.assertEqual(conv_op.get("KernelDims"), k_dims) self.assertEqual(conv_op.get_attr("KernelDims"), k_dims)
def test_fc(self): def test_fc(self):
out_channels = 8 out_channels = 8
nb_bias = True nb_bias = True
fc_op = aidge_core.FC(out_channels, nb_bias).get_operator() fc_op = aidge_core.FC(out_channels, nb_bias).get_operator()
self.assertEqual(fc_op.get("OutChannels"), out_channels) self.assertEqual(fc_op.get_attr("OutChannels"), out_channels)
self.assertEqual(fc_op.get("NoBias"), nb_bias) self.assertEqual(fc_op.get_attr("NoBias"), nb_bias)
def test_matmul(self): def test_matmul(self):
out_channels = 8 out_channels = 8
matmul_op = aidge_core.Matmul(out_channels).get_operator() matmul_op = aidge_core.MatMul(out_channels).get_operator()
self.assertEqual(matmul_op.get("OutChannels"), out_channels) self.assertEqual(matmul_op.get_attr("OutChannels"), out_channels)
def test_producer_1D(self): def test_producer_1D(self):
dims = [5] dims = [5]
...@@ -71,7 +71,7 @@ class test_parameters(unittest.TestCase): ...@@ -71,7 +71,7 @@ class test_parameters(unittest.TestCase):
def test_leaky_relu(self): def test_leaky_relu(self):
negative_slope = 0.25 negative_slope = 0.25
leakyrelu_op = aidge_core.LeakyReLU(negative_slope).get_operator() leakyrelu_op = aidge_core.LeakyReLU(negative_slope).get_operator()
self.assertEqual(leakyrelu_op.get("NegativeSlope"), negative_slope) self.assertEqual(leakyrelu_op.get_attr("NegativeSlope"), negative_slope)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
"""
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
"""
import unittest
import aidge_core
class test_recipies(unittest.TestCase):
"""
"""
def setUp(self):
pass
def tearDown(self):
pass
def test_remove_flatten(self):
graph_view = aidge_core.sequential([
aidge_core.GenericOperator("Flatten", 1, 1, 1, name="Flatten0"),
aidge_core.FC(50, name='0')
])
old_nodes = graph_view.get_nodes()
aidge_core.remove_flatten(graph_view)
self.assertTrue(len(graph_view.get_nodes()) == len(old_nodes) - 1)
self.assertTrue("Flatten0" not in [i.name for i in graph_view.get_nodes()])
self.assertTrue(all([i in old_nodes for i in graph_view.get_nodes()]))
def test_fuse_matmul_add(self):
matmul0 = aidge_core.GenericOperator("MatMul", 1, 2, 1, name="MatMul0")
add0 = aidge_core.Add(name="Add0")
matmul1 = aidge_core.GenericOperator("MatMul", 1, 2, 1, name="MatMul1")
add1 = aidge_core.Add(name="Add1")
graph_view = aidge_core.sequential([matmul0, add0, matmul1, add1])
w0 = aidge_core.Producer([1, 1], name="W0")
w0.add_child(matmul0, 0, 1)
graph_view.add(w0)
b0 = aidge_core.Producer([1], name="B0")
b0.add_child(add0, 0, 1)
graph_view.add(b0)
w1 = aidge_core.Producer([1, 1], name="W1")
w1.add_child(matmul1, 0, 1)
graph_view.add(w1)
b1 = aidge_core.Producer([1], name="B1")
b1.add_child(add1, 0, 1)
graph_view.add(b1)
old_nodes = graph_view.get_nodes()
aidge_core.fuse_mul_add(graph_view)
self.assertTrue(len(graph_view.get_nodes()) == len(old_nodes) - 2)
self.assertTrue("MatMul0" not in [i.name() for i in graph_view.get_nodes()])
self.assertTrue("Add0" not in [i.name() for i in graph_view.get_nodes()])
self.assertTrue("MatMul1" not in [i.name() for i in graph_view.get_nodes()])
self.assertTrue("Add1" not in [i.name() for i in graph_view.get_nodes()])
self.assertTrue("W0" in [i.name() for i in graph_view.get_nodes()])
self.assertTrue("B0" in [i.name() for i in graph_view.get_nodes()])
self.assertTrue("W1" in [i.name() for i in graph_view.get_nodes()])
self.assertTrue("B1" in [i.name() for i in graph_view.get_nodes()])
# TODO : Vérifier que FC bien crée
if __name__ == '__main__':
unittest.main()
"""
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
"""
import unittest
import aidge_core
from functools import reduce
import numpy as np
class test_tensor(unittest.TestCase):
"""
"""
def setUp(self):
pass
def tearDown(self):
pass
def test_getcoord_getidx(self):
dims = [2,2,2]
size = reduce((lambda x, y: x*y), dims)
np_array = np.arange(size).reshape(dims)
t = aidge_core.Tensor(np_array)
for i in range(size):
coord = t.get_coord(i)
idx = t.get_idx(coord)
self.assertEqual(idx, i)
if __name__ == '__main__':
unittest.main()
function(generate_python_binding name target_to_bind) function(generate_python_binding name target_to_bind)
if (PYBIND) add_definitions(-DPYBIND)
add_definitions(-DPYBIND) Include(FetchContent)
Include(FetchContent)
FetchContent_Declare( FetchContent_Declare(
PyBind11 PyBind11
GIT_REPOSITORY https://github.com/pybind/pybind11.git GIT_REPOSITORY https://github.com/pybind/pybind11.git
GIT_TAG v2.10.4 # or a later release GIT_TAG v2.10.4 # or a later release
) )
# Use the New FindPython mode, recommanded. Requires CMake 3.15+ # Use the New FindPython mode, recommanded. Requires CMake 3.15+
find_package(Python COMPONENTS Interpreter Development) find_package(Python COMPONENTS Interpreter Development)
FetchContent_MakeAvailable(PyBind11) FetchContent_MakeAvailable(PyBind11)
message(STATUS "Creating binding for module ${name}") message(STATUS "Creating binding for module ${name}")
file(GLOB_RECURSE pybind_src_files "python_binding/*.cpp") 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 pybind11_add_module(${name} MODULE ${pybind_src_files} "NO_EXTRAS") # NO EXTRA recquired for pip install
target_include_directories(${name} PUBLIC "python_binding") target_include_directories(${name} PUBLIC "python_binding")
target_link_libraries(${name} PUBLIC ${target_to_bind}) target_link_libraries(${name} PUBLIC ${target_to_bind})
endif()
endfunction() endfunction()
...@@ -34,17 +34,27 @@ ...@@ -34,17 +34,27 @@
#include "aidge/operator/BatchNorm.hpp" #include "aidge/operator/BatchNorm.hpp"
#include "aidge/operator/Conv.hpp" #include "aidge/operator/Conv.hpp"
#include "aidge/operator/ConvDepthWise.hpp" #include "aidge/operator/ConvDepthWise.hpp"
#include "aidge/operator/Div.hpp"
#include "aidge/operator/FC.hpp" #include "aidge/operator/FC.hpp"
#include "aidge/operator/GenericOperator.hpp" #include "aidge/operator/GenericOperator.hpp"
#include "aidge/operator/Matmul.hpp" #include "aidge/operator/MatMul.hpp"
#include "aidge/operator/MaxPooling.hpp"
#include "aidge/operator/MetaOperator.hpp" #include "aidge/operator/MetaOperator.hpp"
#include "aidge/operator/MetaOperatorDefs.hpp"
#include "aidge/operator/Mul.hpp"
#include "aidge/operator/Operator.hpp" #include "aidge/operator/Operator.hpp"
#include "aidge/operator/Pad.hpp"
#include "aidge/operator/Producer.hpp" #include "aidge/operator/Producer.hpp"
#include "aidge/operator/Pow.hpp"
#include "aidge/operator/ReLU.hpp" #include "aidge/operator/ReLU.hpp"
#include "aidge/operator/Scaling.hpp"
#include "aidge/operator/Softmax.hpp" #include "aidge/operator/Softmax.hpp"
#include "aidge/operator/Sqrt.hpp"
#include "aidge/operator/Sub.hpp"
#include "aidge/scheduler/Scheduler.hpp" #include "aidge/scheduler/Scheduler.hpp"
#include "aidge/utils/CParameter.hpp" #include "aidge/utils/Attributes.hpp"
#include "aidge/utils/Parameter.hpp" #include "aidge/utils/StaticAttributes.hpp"
#include "aidge/utils/DynamicAttributes.hpp"
#include "aidge/utils/Recipies.hpp" #include "aidge/utils/Recipies.hpp"
#include "aidge/utils/Registrar.hpp" #include "aidge/utils/Registrar.hpp"
#include "aidge/utils/Types.h" #include "aidge/utils/Types.h"
......
...@@ -14,13 +14,17 @@ ...@@ -14,13 +14,17 @@
#include <cstddef> #include <cstddef>
#include <vector> #include <vector>
#include <memory>
#include "aidge/utils/Types.h" #include "aidge/utils/Types.h"
namespace Aidge { namespace Aidge {
class Operator;
class OperatorImpl { class OperatorImpl {
public: public:
virtual void forward(){}; OperatorImpl(const Operator& op);
virtual void backward() {} virtual void forward();
virtual void backward();
/** /**
* @brief Minimum amount of data from a specific input required by the * @brief Minimum amount of data from a specific input required by the
...@@ -29,13 +33,13 @@ public: ...@@ -29,13 +33,13 @@ public:
* @param inputIdx Index of the input analysed. * @param inputIdx Index of the input analysed.
* @return std::size_t * @return std::size_t
*/ */
virtual NbElts_t getNbRequiredData(const IOIndex_t inputIdx) const = 0; virtual NbElts_t getNbRequiredData(const IOIndex_t inputIdx) const;
// Amount of input data that cannot be overwritten during the execution. // Amount of input data that cannot be overwritten during the execution.
virtual NbElts_t getNbRequiredProtected(const IOIndex_t inputIdx) const = 0; virtual NbElts_t getNbRequiredProtected(const IOIndex_t inputIdx) const;
// Memory required at an output for a given input size. // Memory required at an output for a given input size.
virtual NbElts_t getRequiredMemory(const IOIndex_t outputIdx, const std::vector<DimSize_t> &inputsSize) const = 0; virtual NbElts_t getRequiredMemory(const IOIndex_t outputIdx, const std::vector<DimSize_t> &inputsSize) const;
/** /**
* @brief Total amount of consumed data from a specific input. * @brief Total amount of consumed data from a specific input.
...@@ -43,17 +47,28 @@ public: ...@@ -43,17 +47,28 @@ public:
* @param inputIdx Index of the input analysed. * @param inputIdx Index of the input analysed.
* @return DimSize_t * @return DimSize_t
*/ */
virtual NbElts_t getNbConsumedData(const IOIndex_t inputIdx) const = 0; virtual NbElts_t getNbConsumedData(const IOIndex_t inputIdx) const;
/** /**
* @brief TOtal amount of produced data ready to be used on a specific output. * @brief Total amount of produced data ready to be used on a specific output.
* *
* @param outputIdx Index of the output analysed. * @param outputIdx Index of the output analysed.
* @return DimSize_t * @return DimSize_t
*/ */
virtual NbElts_t getNbProducedData(const IOIndex_t outputIdx) const = 0; virtual NbElts_t getNbProducedData(const IOIndex_t outputIdx) const;
/**
* @brief Update the Consummer Producer system by simulating the consumption and production of i/o
*
*/
virtual void updateConsummerProducer();
virtual ~OperatorImpl() = default; virtual ~OperatorImpl() = default;
protected:
const Operator &mOp;
std::vector<NbElts_t> mNbConsumedData;
std::vector<NbElts_t> mNbProducedData;
}; };
} // namespace Aidge } // namespace Aidge
......
...@@ -27,6 +27,9 @@ public: ...@@ -27,6 +27,9 @@ public:
{ {
printf("Cannot set raw pointer for backend %s\n", mBackend); printf("Cannot set raw pointer for backend %s\n", mBackend);
}; };
virtual void* getRaw(std::size_t /*idx*/)=0;
virtual std::size_t scalarSize() const = 0; // Size of one scalar (in bytes) virtual std::size_t scalarSize() const = 0; // Size of one scalar (in bytes)
constexpr const char *backend() const { return mBackend; } constexpr const char *backend() const { return mBackend; }
virtual ~TensorImpl() = default; virtual ~TensorImpl() = default;
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
#ifndef AIDGE_DATA_H_ #ifndef AIDGE_DATA_H_
#define AIDGE_DATA_H_ #define AIDGE_DATA_H_
#include "aidge/utils/Parameter.hpp" #include "aidge/utils/Attributes.hpp"
namespace Aidge { namespace Aidge {
enum class DataType { enum class DataType {
......
...@@ -446,29 +446,45 @@ class Tensor : public Data, ...@@ -446,29 +446,45 @@ class Tensor : public Data,
*/ */
bool empty() const { return mDims.empty(); } bool empty() const { return mDims.empty(); }
template <typename expectedType, std::array<std::size_t, 1>::size_type DIM> template <typename expectedType>
constexpr expectedType &get(std::array<std::size_t, DIM> idx) { expectedType& get(std::size_t idx){
assert(DIM == mDims.size()); // TODO : add assert expected Type compatible with datatype
assert(mImpl); // TODO : add assert idx < Size
std::size_t unfoldedIdx = 0; return *reinterpret_cast<expectedType *>(mImpl->getRaw(idx));
for (std::size_t i = 0; i < DIM - std::size_t(1); ++i) { }
unfoldedIdx = (unfoldedIdx + idx[i]) * mDims[i + 1];
} template <typename expectedType>
unfoldedIdx += idx[DIM - 1]; expectedType& get(std::vector<std::size_t> coordIdx){
return static_cast<expectedType *>(mImpl->rawPtr())[unfoldedIdx]; return get<expectedType>(getIdx(coordIdx));
}
template <typename expectedType>
void set(std::size_t idx, expectedType value){
// TODO : add assert expected Type compatible with datatype
// TODO : add assert idx < Size
void* dataPtr = mImpl->getRaw(idx);
std::memcpy(dataPtr, &value, sizeof(expectedType));
}
template <typename expectedType>
void set(std::vector<std::size_t> coordIdx, expectedType value){
set<expectedType>(getIdx(coordIdx), value);
} }
std::string toString() { std::string toString() {
if (dims().empty()) { return "{}"; } if (dims().empty()) { return "{}"; }
std::string res; std::string res;
std::size_t dim = 0; std::size_t dim = 0;
std::size_t *dimVals = new std::size_t[nbDims()];
for (std::size_t i = 0; i < nbDims(); ++i) {
dimVals[i] = 0;
}
std::size_t counter = 0; std::size_t counter = 0;
res += "{\n"; if (nbDims()>=2) {
if (nbDims()>=2){ std::size_t *dimVals = new std::size_t[nbDims()];
for (std::size_t i = 0; i < nbDims(); ++i) {
dimVals[i] = 0;
}
// std::vector<std::size_t> dimVals = std::vector<std::size_t>(nbDims(), 0);
res += "{\n";
while (counter < mSize) { while (counter < mSize) {
std::string spaceString = std::string((dim+1)<<1,' '); std::string spaceString = std::string((dim+1)<<1,' ');
if (dim < nbDims()-2) { if (dim < nbDims()-2) {
...@@ -517,31 +533,35 @@ class Tensor : public Data, ...@@ -517,31 +533,35 @@ class Tensor : public Data,
} }
res += "\n"; res += "\n";
} }
if (dim == 0) {
break;
}
dimVals[dim--] = 0; dimVals[dim--] = 0;
dimVals[dim]++; dimVals[dim]++;
} }
} }
for(int i = static_cast<int>(dim); i>=0; --i) { delete[] dimVals;
for(int i = static_cast<int>(dim); i > 0; --i) {
res += std::string((dim+1)<<1,' ') + "}\n"; res += std::string((dim+1)<<1,' ') + "}\n";
} }
}else{ } else {
res += "{";
for (DimSize_t j = 0; j < dims()[0]; ++j) { for (DimSize_t j = 0; j < dims()[0]; ++j) {
switch (mDataType) switch (mDataType)
{ {
case DataType::Int32: case DataType::Int32:
res += " " + std::to_string(static_cast<int *>(mImpl->rawPtr())[j]) + ((j < dims()[0]-1) ? "," : "\n"); res += " " + std::to_string(static_cast<int *>(mImpl->rawPtr())[j]) + ((j < dims()[0]-1) ? "," : "");
break; break;
case DataType::Float64: case DataType::Float64:
res += " " + std::to_string(static_cast<double *>(mImpl->rawPtr())[j]) + ((j < dims()[0]-1) ? "," : "\n"); res += " " + std::to_string(static_cast<double *>(mImpl->rawPtr())[j]) + ((j < dims()[0]-1) ? "," : "");
break; break;
default: default:
res += " " + std::to_string(static_cast<float *>(mImpl->rawPtr())[j]) + ((j < dims()[0]-1) ? "," : "\n"); res += " " + std::to_string(static_cast<float *>(mImpl->rawPtr())[j]) + ((j < dims()[0]-1) ? "," : "");
break; break;
} }
} }
} }
res += "}"; res += "}";
return res; return res;
} }
...@@ -559,6 +579,42 @@ class Tensor : public Data, ...@@ -559,6 +579,42 @@ class Tensor : public Data,
return mGrad; return mGrad;
} }
/**
* @brief From the the 1D index, return the coordinate of an element in the tensor.
*
* @param flatIdx 1D index of the value considering a flatten tensor.
* @return std::vector<DimSize_t>
*/
std::vector<std::size_t> getCoord(std::size_t flatIdx) const {
std::vector<std::size_t> coordIdx = std::vector<std::size_t>(mDims.size());
std::size_t idx = flatIdx;
for (std::size_t i = mDims.size() - 1; i > 0; --i){
coordIdx[i] = (idx % mDims[i]);
idx/=mDims[i];
}
coordIdx[0] = idx % mDims[0];
return coordIdx;
}
/**
* @brief From the coordinate returns the 1D index of an element in the tensor.
*
* @param coordIdx Coordinate to an element in the tensor
* @return DimSize_t
*/
std::size_t getIdx(std::vector<std::size_t> coordIdx) const {
// std::size_t flatIdx = 0;
// std::size_t stride = 1;
std::size_t flatIdx = 0;
assert(coordIdx.size() == mDims.size() && "Coordinates does not match number of dimensions");
std::size_t i = 0;
for(; i < mDims.size() - 1; ++i){
assert(coordIdx[i] < mDims[i] && "Coordinates dimensions does not fit the dimensions of the tensor");
flatIdx = (flatIdx + coordIdx[i]) * mDims[i + 1];
}
return flatIdx + coordIdx[i];
}
private: private:
///\bug not protected against overflow ///\bug not protected against overflow
std::size_t computeSize() { std::size_t computeSize() {
......
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