From 41a05be8cbb22e6d2aa7b2da5d58b61ae9f15d51 Mon Sep 17 00:00:00 2001 From: Axel Farrugia <axel.farrugia@cea.fr> Date: Tue, 18 Feb 2025 11:28:54 +0100 Subject: [PATCH 1/9] [Feat](Exports) Add a copy_folder function and allow the copies to be done through simlinks --- aidge_core/export_utils/__init__.py | 2 +- aidge_core/export_utils/code_generation.py | 23 +++++++++++++++++++-- aidge_core/export_utils/export_registry.py | 3 +++ aidge_core/export_utils/scheduler_export.py | 8 +++++-- 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/aidge_core/export_utils/__init__.py b/aidge_core/export_utils/__init__.py index 72472eee0..a14fc63b1 100644 --- a/aidge_core/export_utils/__init__.py +++ b/aidge_core/export_utils/__init__.py @@ -1,5 +1,5 @@ from .node_export import ExportNode, ExportNodeCpp -from .code_generation import generate_file, generate_str, copy_file +from .code_generation import generate_file, generate_str, copy_file, copy_folder from .export_registry import ExportLib from .scheduler_export import scheduler_export from .tensor_export import tensor_to_c, generate_input_file diff --git a/aidge_core/export_utils/code_generation.py b/aidge_core/export_utils/code_generation.py index 4f0f4634d..42ae19f79 100644 --- a/aidge_core/export_utils/code_generation.py +++ b/aidge_core/export_utils/code_generation.py @@ -44,10 +44,29 @@ def generate_str(template_path: Union[Path, str], **kwargs) -> str: return Environment(loader=FileSystemLoader( template_path.parent), undefined=StrictUndefined, keep_trailing_newline=True).get_template(template_path.name).render(kwargs) -def copy_file(filename, dst_folder): +def copy_file(filename, dst_folder, symlink=False): + """Copy the given file into the given dst path + The symlink arg allows to make a symbolic link instead of copying the file. + """ # If directory doesn't exist, create it if not os.path.exists(dst_folder): os.makedirs(dst_folder) - shutil.copy(filename, dst_folder) + if symlink: + dst_folder += "/" + os.path.basename(filename) + if not os.path.exists(dst_folder): + os.symlink(filename, dst_folder) + else: + shutil.copy(filename, dst_folder) + +def copy_folder(foldername, dst_folder, symlink=False): + """Copy the given folder into the given dst path + The symlink arg allows to make a symbolic link instead of copying the file. + """ + + if symlink: + os.symlink(foldername, dst_folder) + else: + shutil.copytree(foldername, dst_folder, dirs_exist_ok=True) + \ No newline at end of file diff --git a/aidge_core/export_utils/export_registry.py b/aidge_core/export_utils/export_registry.py index 8927ae516..01329e6a5 100644 --- a/aidge_core/export_utils/export_registry.py +++ b/aidge_core/export_utils/export_registry.py @@ -40,6 +40,9 @@ class ExportLib(aidge_core.OperatorImpl): # key: Path where static file is # Value: Path where to copy the file relative to the export root static_files: Dict[str, str] = {} + # key: Path where static folder is + # Value: Path where to copy the folder relative to the export root + static_folders: Dict[str, str] = {} # Main memory section mem_section = None # Custom forward generation jinja file diff --git a/aidge_core/export_utils/scheduler_export.py b/aidge_core/export_utils/scheduler_export.py index 8aaedc18d..aaca6b76a 100644 --- a/aidge_core/export_utils/scheduler_export.py +++ b/aidge_core/export_utils/scheduler_export.py @@ -2,7 +2,7 @@ import aidge_core import os import shutil from pathlib import Path -from aidge_core.export_utils import ExportLib, generate_file, copy_file +from aidge_core.export_utils import ExportLib, generate_file, copy_file, copy_folder from typing import List, Tuple @@ -208,4 +208,8 @@ def scheduler_export(scheduler, export_folder_path: str, export_lib: ExportLib = if export_lib is not None: # Copy all static files in the export for source, destination in export_lib.static_files.items(): - copy_file(source, str(export_folder / destination)) + copy_file(source, str(export_folder / destination), test_mode) + + # Copy all static folders in the export + for source, destination in export_lib.static_folders.items(): + copy_folder(source, str(export_folder / destination), test_mode) -- GitLab From afaa5157ba50a3c11c170b07685679f1b981c7fa Mon Sep 17 00:00:00 2001 From: Axel Farrugia <axel.farrugia@cea.fr> Date: Wed, 5 Mar 2025 13:34:06 +0100 Subject: [PATCH 2/9] [Fix] copy_folder() function now create the parent directory before creating the symlink --- aidge_core/export_utils/code_generation.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/aidge_core/export_utils/code_generation.py b/aidge_core/export_utils/code_generation.py index 42ae19f79..8b3bf65ed 100644 --- a/aidge_core/export_utils/code_generation.py +++ b/aidge_core/export_utils/code_generation.py @@ -44,7 +44,7 @@ def generate_str(template_path: Union[Path, str], **kwargs) -> str: return Environment(loader=FileSystemLoader( template_path.parent), undefined=StrictUndefined, keep_trailing_newline=True).get_template(template_path.name).render(kwargs) -def copy_file(filename, dst_folder, symlink=False): +def copy_file(filename: Union[Path, str], dst_folder: Union[Path, str], symlink=False): """Copy the given file into the given dst path The symlink arg allows to make a symbolic link instead of copying the file. """ @@ -60,11 +60,16 @@ def copy_file(filename, dst_folder, symlink=False): else: shutil.copy(filename, dst_folder) -def copy_folder(foldername, dst_folder, symlink=False): +def copy_folder(foldername: Union[Path, str], dst_folder: Union[Path, str], symlink=False): """Copy the given folder into the given dst path The symlink arg allows to make a symbolic link instead of copying the file. """ + # If the parent directory doesn't exist, create it + parent_dir = Path(dst_folder).parent + if not os.path.exists(parent_dir): + os.makedirs(parent_dir) + if symlink: os.symlink(foldername, dst_folder) else: -- GitLab From 8b3bb72973e03311f6911fc9ce58f1e85e3367f9 Mon Sep 17 00:00:00 2001 From: Axel Farrugia <axel.farrugia@cea.fr> Date: Tue, 18 Mar 2025 16:52:54 +0100 Subject: [PATCH 3/9] [Feat](Exports) Add label export in generate_main_cpp() function and change the default inputs and labels destination folder from "ROOT" to "ROOT/data" --- aidge_core/export_utils/generate_main.py | 29 ++++++++++---- aidge_core/export_utils/templates/main.jinja | 38 ++++++++++++++++--- .../export_utils/templates/main_compare.jinja | 4 +- 3 files changed, 56 insertions(+), 15 deletions(-) diff --git a/aidge_core/export_utils/generate_main.py b/aidge_core/export_utils/generate_main.py index 57fc68bca..b8aa14517 100644 --- a/aidge_core/export_utils/generate_main.py +++ b/aidge_core/export_utils/generate_main.py @@ -1,8 +1,8 @@ import aidge_core from pathlib import Path -from aidge_core.export_utils import generate_file, data_conversion +from aidge_core.export_utils import generate_file, data_conversion, generate_input_file -def generate_main_cpp(export_folder: str, graph_view: aidge_core.GraphView, inputs_tensor=None) -> None: +def generate_main_cpp(export_folder: str, graph_view: aidge_core.GraphView, inputs_tensor=None, labels=None) -> None: """ Generate a C++ file to manage the forward pass of a model using the given graph structure. @@ -18,7 +18,10 @@ def generate_main_cpp(export_folder: str, graph_view: aidge_core.GraphView, inpu ordered input/output data within the computational graph. :type graph_view: aidge_core.graph_view :param inputs_tensor: **For future** argument to provide tensor to use in the main function, not implemented yet! - :type inputs_tensor: None + By default, the input of the given graph will be exported. + :type inputs_tensor: aidge_core.Tensor + :param labels: Argument to provide labels tensor to generate and use in the main function. + :type labels: aidge_core.Tensor :raises RuntimeError: If there is an inconsistency in the output arguments (names, data types, sizes), indicating an internal bug in the graph representation. """ @@ -41,7 +44,18 @@ def generate_main_cpp(export_folder: str, graph_view: aidge_core.GraphView, inpu else: aidge_core.Log.notice(f"No input tensor set for {in_name}, main generated will not be functionnal after code generation.") else: - aidge_core.export_utils.generate_input_file(export_folder=export_folder, array_name=in_name, tensor=input_tensor) + # Generate input file + generate_input_file( + export_folder=str(Path(export_folder) / "data"), + array_name=in_name, + tensor=input_tensor) + if labels is not None: + # Generate labels + generate_input_file( + export_folder=str(Path(export_folder) / "data"), + array_name="labels", + tensor=labels + ) for out_node, out_id in gv_outputs: outputs_name.append(f"{out_node.name()}_output_{out_id}") @@ -60,7 +74,8 @@ def generate_main_cpp(export_folder: str, graph_view: aidge_core.GraphView, inpu inputs_name=inputs_name, outputs_name=outputs_name, outputs_dtype=outputs_dtype, - outputs_size=outputs_size + outputs_size=outputs_size, + labels=(labels is not None) ) @@ -103,7 +118,7 @@ def generate_main_compare_cpp(export_folder: str, graph_view: aidge_core.GraphVi else: aidge_core.Log.notice(f"No input tensor set for {in_name}, main generated will not be functionnal after code generation.") else: - aidge_core.export_utils.generate_input_file(export_folder=export_folder, array_name=in_name, tensor=input_tensor) + generate_input_file(export_folder=export_folder, array_name=in_name, tensor=input_tensor) for out_node, out_id in gv_outputs: out_name = f"{out_node.name()}_output_{out_id}" @@ -114,7 +129,7 @@ def generate_main_compare_cpp(export_folder: str, graph_view: aidge_core.GraphVi if out_tensor is None or out_tensor.undefined() or not out_tensor.has_impl(): aidge_core.Log.notice(f"No input tensor set for {out_name}, main generated will not be functionnal after code generation.") else: - aidge_core.export_utils.generate_input_file(export_folder=export_folder, array_name=out_name+"_expected", tensor=out_tensor) + generate_input_file(export_folder=export_folder, array_name=out_name+"_expected", tensor=out_tensor) if len(outputs_name) != len(outputs_dtype) or len(outputs_name) != len(outputs_size): raise RuntimeError("FATAL: Output args list does not have the same length this is an internal bug.") diff --git a/aidge_core/export_utils/templates/main.jinja b/aidge_core/export_utils/templates/main.jinja index 697a97b53..b44f40a90 100644 --- a/aidge_core/export_utils/templates/main.jinja +++ b/aidge_core/export_utils/templates/main.jinja @@ -1,11 +1,14 @@ #include <iostream> #include "forward.hpp" -{% for name in inputs_name %} -#include "{{ name }}.h" -{% endfor %} +{%- for name in inputs_name %} +#include "data/{{ name }}.h" +{%- endfor %} +{%- if labels %} +#include "data/labels.h" +{%- endif %} -{% set printf_formats = { +{%- set printf_formats = { "double": "%lf", "float": "%f", "int8_t": "%hhd", @@ -28,13 +31,36 @@ int main() // Call the forward function {{ func_name }}({{ inputs_name|join(", ") }}{% if inputs_name %}, {% endif %}&{{ outputs_name|join(", &") }}); - // Print the results of each output + // Print the results + {%- if labels %} + int prediction; + int confidence; + {%- for o in range(outputs_name | length) %} + prediction = 0; + confidence = {{ outputs_name[o] }}[0]; + + for (int o = 0; o < {{ outputs_size[0] }}; ++o) { + if ({{ outputs_name[0] }}[o] > confidence) { + prediction = o; + confidence = {{ outputs_name[0] }}[o]; + } + } + + printf("Prediction : %d (%d)\n", prediction, confidence); + printf("Label : %d\n", labels[{{ o }}]); + + {%- endfor %} + {%- else %} + {%- for o in range(outputs_name | length) %} + printf("{{ outputs_name[o] }}:\n"); for (int o = 0; o < {{ outputs_size[o] }}; ++o) { printf("{{ printf_formats[outputs_dtype[o]] }} ", {{ outputs_name[o] }}[o]); } printf("\n"); - {% endfor %} + + {%- endfor %} + {%- endif %} return 0; } diff --git a/aidge_core/export_utils/templates/main_compare.jinja b/aidge_core/export_utils/templates/main_compare.jinja index 3cc4c986d..7113fb0f2 100644 --- a/aidge_core/export_utils/templates/main_compare.jinja +++ b/aidge_core/export_utils/templates/main_compare.jinja @@ -16,12 +16,12 @@ // Inputs {% for name in inputs_name %} -#include "{{ name }}.h" +#include "data/{{ name }}.h" {% endfor %} // Outputs {% for name in outputs_name %} -#include "{{ name }}_expected.h" +#include "data/{{ name }}_expected.h" {% endfor %} int main() -- GitLab From 264e3a21a93a44baed46c24cb269839779102130 Mon Sep 17 00:00:00 2001 From: Axel Farrugia <axel.farrugia@cea.fr> Date: Tue, 18 Mar 2025 16:55:32 +0100 Subject: [PATCH 4/9] [Feat](Exports) Add a function to remove the optional inputs from the inputs list so they are not exported --- aidge_core/export_utils/__init__.py | 1 + aidge_core/export_utils/export_utils.py | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 aidge_core/export_utils/export_utils.py diff --git a/aidge_core/export_utils/__init__.py b/aidge_core/export_utils/__init__.py index a14fc63b1..9f5214754 100644 --- a/aidge_core/export_utils/__init__.py +++ b/aidge_core/export_utils/__init__.py @@ -4,3 +4,4 @@ from .export_registry import ExportLib from .scheduler_export import scheduler_export from .tensor_export import tensor_to_c, generate_input_file from .generate_main import generate_main_cpp, generate_main_compare_cpp +from .export_utils import remove_optional_inputs diff --git a/aidge_core/export_utils/export_utils.py b/aidge_core/export_utils/export_utils.py new file mode 100644 index 000000000..fd6624287 --- /dev/null +++ b/aidge_core/export_utils/export_utils.py @@ -0,0 +1,20 @@ +import aidge_core + +def remove_optional_inputs(graph_view: aidge_core.GraphView): + """ Remove optional inputs from the ordered_list of the model + + There are 3 inputs categories : + - 0 : Data + - 1 : Parameters + - 2 : Optional Inputs + + :param graph_view: An instance of :py:class:`aidge_core.graph_view`, providing access to nodes and + ordered input/output data within the computational graph. + :type graph_view: aidge_core.graph_view + """ + + inputNodes = [] + for n in graph_view.get_ordered_inputs(): + if n[0].get_operator().input_category(n[1]) in [aidge_core.InputCategory(0), aidge_core.InputCategory(1)]: + inputNodes.append(n) + graph_view.set_ordered_inputs(inputNodes) -- GitLab From 81f9c274bbb14a4c3b9a0126908d942e2f2d8e3e Mon Sep 17 00:00:00 2001 From: Axel Farrugia <axel.farrugia@cea.fr> Date: Tue, 18 Mar 2025 16:57:48 +0100 Subject: [PATCH 5/9] [Chore](Exports) Change from test_mode to dev_mode for coherence --- aidge_core/export_utils/scheduler_export.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/aidge_core/export_utils/scheduler_export.py b/aidge_core/export_utils/scheduler_export.py index aaca6b76a..a6b590cb3 100644 --- a/aidge_core/export_utils/scheduler_export.py +++ b/aidge_core/export_utils/scheduler_export.py @@ -6,7 +6,7 @@ from aidge_core.export_utils import ExportLib, generate_file, copy_file, copy_fo from typing import List, Tuple -def scheduler_export(scheduler, export_folder_path: str, export_lib: ExportLib = None, memory_manager=None, memory_manager_args=None, test_mode=False) -> None: +def scheduler_export(scheduler, export_folder_path: str, export_lib: ExportLib = None, memory_manager=None, memory_manager_args=None, dev_mode=False) -> None: """Exports an aidge_core.Scheduler to C++ code. This function generates files for a given computation graph, including forward-pass functions, @@ -57,8 +57,12 @@ def scheduler_export(scheduler, export_folder_path: str, export_lib: ExportLib = :type memory_manager: callable :param memory_manager_args: Additional arguments passed to `memory_manager`. Defaults to an empty dictionary. :type memory_manager_args: dict, optional - :param test_mode: Additional argument which may be used during forward generation. - :type test_mode: bool, optional + :param dev_mode: Wether or not the developer mode is enabled. If enabled, the export files + will be symlinks from the aidge export module. Therefore, modifying + a file within the export will change the module as well. + The dev_mode flag is also passed to the forward jinja templates to allow export + customization (ie. Adding a debug mode for instance). + :type dev_mode: bool, optional """ graphview = scheduler.graph_view() export_folder = Path().absolute() / export_folder_path @@ -181,7 +185,7 @@ def scheduler_export(scheduler, export_folder_path: str, export_lib: ExportLib = inputs_dtype=inputs_dtype, outputs_name=outputs_name, outputs_dtype=outputs_dtype, - test_mode=test_mode, + dev_mode=dev_mode, list_node_names=list_node_names ) @@ -199,7 +203,7 @@ def scheduler_export(scheduler, export_folder_path: str, export_lib: ExportLib = inputs_dtype=inputs_dtype, outputs_name=outputs_name, outputs_dtype=outputs_dtype, - test_mode=test_mode + dev_mode=dev_mode ) if len(outputs_name) != len(outputs_dtype) or len(outputs_name) != len(outputs_size): @@ -208,8 +212,8 @@ def scheduler_export(scheduler, export_folder_path: str, export_lib: ExportLib = if export_lib is not None: # Copy all static files in the export for source, destination in export_lib.static_files.items(): - copy_file(source, str(export_folder / destination), test_mode) + copy_file(source, str(export_folder / destination), dev_mode) # Copy all static folders in the export for source, destination in export_lib.static_folders.items(): - copy_folder(source, str(export_folder / destination), test_mode) + copy_folder(source, str(export_folder / destination), dev_mode) -- GitLab From 58890a40db9f4fe711d2875f869094c434fa3916 Mon Sep 17 00:00:00 2001 From: Axel Farrugia <axel.farrugia@cea.fr> Date: Tue, 18 Mar 2025 16:58:40 +0100 Subject: [PATCH 6/9] [Chore](Exports) Add access to data_conversion functions --- aidge_core/export_utils/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/aidge_core/export_utils/__init__.py b/aidge_core/export_utils/__init__.py index 9f5214754..ddd810515 100644 --- a/aidge_core/export_utils/__init__.py +++ b/aidge_core/export_utils/__init__.py @@ -4,4 +4,5 @@ from .export_registry import ExportLib from .scheduler_export import scheduler_export from .tensor_export import tensor_to_c, generate_input_file from .generate_main import generate_main_cpp, generate_main_compare_cpp +from .data_conversion import aidge2c, aidge2export_type from .export_utils import remove_optional_inputs -- GitLab From 3ea64436468acc4b5a95b71c92726f85d89dc081 Mon Sep 17 00:00:00 2001 From: Axel Farrugia <axel.farrugia@cea.fr> Date: Fri, 21 Mar 2025 10:42:01 +0100 Subject: [PATCH 7/9] [Fix](Exports) labels are now generted once and optional inputs are ignored --- aidge_core/export_utils/generate_main.py | 35 ++++++++++++++---------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/aidge_core/export_utils/generate_main.py b/aidge_core/export_utils/generate_main.py index b8aa14517..ae86116dc 100644 --- a/aidge_core/export_utils/generate_main.py +++ b/aidge_core/export_utils/generate_main.py @@ -32,30 +32,35 @@ def generate_main_cpp(export_folder: str, graph_view: aidge_core.GraphView, inpu gv_inputs: list[tuple[aidge_core.Node, int]] = graph_view.get_ordered_inputs() gv_outputs: list[tuple[aidge_core.Node, int]] = graph_view.get_ordered_outputs() + # Generate input file(s) for in_node, in_idx in gv_inputs: in_node_input, in_node_input_idx = in_node.input(in_idx) in_name = f"{in_node.name()}_input_{in_idx}" if in_node_input is None else f"{in_node_input.name()}_output_{in_node_input_idx}" - inputs_name.append(in_name) input_tensor = in_node.get_operator().get_input(in_idx) - if input_tensor is None or input_tensor.undefined() or not input_tensor.has_impl(): - if inputs_tensor is not None: - aidge_core.Log.notice("No support for inputs_tensor argument yet.") - aidge_core.Log.notice(f"No input tensor set for {in_name}, main generated will not be functionnal after code generation.") - else: - aidge_core.Log.notice(f"No input tensor set for {in_name}, main generated will not be functionnal after code generation.") + # if input_tensor is None or input_tensor.undefined() or not input_tensor.has_impl(): + # if inputs_tensor is not None: + # aidge_core.Log.notice("No support for inputs_tensor argument yet.") + # aidge_core.Log.notice(f"No input tensor set for {in_name}, main generated will not be functionnal after code generation.") + # else: + # aidge_core.Log.notice(f"No input tensor set for {in_name}, main generated will not be functionnal after code generation.") + + # Ignore optional inputs + if in_node.get_operator().input_category(in_idx) == aidge_core.InputCategory(2): + aidge_core.Log.notice(f"Ignoring optional input {in_name}.") else: - # Generate input file + inputs_name.append(in_name) generate_input_file( export_folder=str(Path(export_folder) / "data"), array_name=in_name, tensor=input_tensor) - if labels is not None: - # Generate labels - generate_input_file( - export_folder=str(Path(export_folder) / "data"), - array_name="labels", - tensor=labels - ) + + # Generate labels file + if labels is not None: + generate_input_file( + export_folder=str(Path(export_folder) / "data"), + array_name="labels", + tensor=labels + ) for out_node, out_id in gv_outputs: outputs_name.append(f"{out_node.name()}_output_{out_id}") -- GitLab From a0f56bb73cc4137fac8e4e98cbe9feb87987c469 Mon Sep 17 00:00:00 2001 From: Axel Farrugia <axel.farrugia@cea.fr> Date: Fri, 21 Mar 2025 10:43:10 +0100 Subject: [PATCH 8/9] [Feat](Exports) Change the kernels_to_copy system The old system had some limitations : - Not possible to chose a destination path different from the source path - The copied kernel would be automatically included in the fwd file, sometime leading to unused includes --- aidge_core/export_utils/node_export.py | 61 +++++++++++++++++++++----- 1 file changed, 49 insertions(+), 12 deletions(-) diff --git a/aidge_core/export_utils/node_export.py b/aidge_core/export_utils/node_export.py index c24727adf..3247a7ffb 100644 --- a/aidge_core/export_utils/node_export.py +++ b/aidge_core/export_utils/node_export.py @@ -364,9 +364,9 @@ class ExportNodeCpp(ExportNode): :var include_list: List of include paths (e.g., "include/toto.hpp") to be added to the generated export files. Must be defined before export; raises an error if undefined. :vartype include_list: list[str] - :var kernels_to_copy: List of paths to kernel files that should be copied during - export. The kernels are copied to ``kernels_path``, and are automatically - added to the include list. + :var kernels_to_copy: A list of dict holding src and dst kernels paths to copy in the export. + export. The kernels are copied in dst_path (default : self.kernels_path). + They are automatically added to the include list unless the fwd_include option is set to False. :vartype kernels_to_copy: list[str] :var kernels_path: Path where all kernels are stored in the export, prefixed by the `export_root`. Defaults to "include/kernels". @@ -377,6 +377,12 @@ class ExportNodeCpp(ExportNode): :var config_extension: File extension for the configuration files, typically for header files. Defaults to "h". :vartype config_extension: str + :var dev_mode: Wether or not the developer mode is enabled. If enabled, the export files + will be symlinks from the aidge export module. Therefore, modifying + a file within the export will change the module as well. + The dev_mode flag is also passed to the forward jinja templates to allow export + customization (ie. Adding a debug mode for instance). + :vartype dev_mode: bool """ # Path to the template defining how to export the node definition @@ -385,16 +391,40 @@ class ExportNodeCpp(ExportNode): forward_template: str = None # List of includes to add example "include/toto.hpp" include_list: list = None - # A list of path of kernels to copy in the export - # kernels are copied in str(export_folder / "include" / "kernels") - # They are automatically added to the include list. - kernels_to_copy: list = None + # A list of dict holding src and dst kernels paths to copy in the export. + # kernels are copied in dst_path (default : self.kernels_path) + # They are automatically added to the include list unless the fwd_include option is set to False. + kernels_to_copy: list[dict] = None # Path where all the kernels are stored in the export (prefixed by export_root) kernels_path: str = "include/kernels" # Path of config folders config_path: str = "include/layers" # Config_folder_extension config_extension: str = "h" + # Dev mode - Symlink copy + dev_mode: bool = False + + + def add_kernel_to_copy(self, kernel_src_path: str, kernel_dst_path: str = kernels_path, fwd_include: bool = True): + """ Add a kernel to the kernels_to_copy list of dict. + + :param kernel_src_path: File path for the kernel to copy within the export module. + :type kernel_src_path: str + :param kernel_dst_path: File path for the kernel to copy within the generated export. + :type kernel_dst_path: str + :param fwd_include: Wether the kernel is included in the generated forward file or not. + :type fwd_include: bool + """ + + if self.kernels_to_copy is None: + self.kernels_to_copy = [] + + kernel_to_copy: dict = { + "src_path": kernel_src_path, + "dst_path": kernel_dst_path, + "fwd_include": fwd_include + } + self.kernels_to_copy.append(kernel_to_copy) def export(self, export_folder: str): @@ -419,13 +449,20 @@ class ExportNodeCpp(ExportNode): kernel_include_list = [] for kernel in self.kernels_to_copy: - kernel_path = Path(kernel) + + # Copy the kernel file + kernel_src_path = Path(kernel["src_path"]) + kernel_dst_path = Path(kernel["dst_path"]) code_generation.copy_file( - kernel_path, - str(export_folder / self.kernels_path) + kernel_src_path, + str(export_folder / kernel_dst_path), + self.dev_mode ) - kernel_include_list.append( - self.kernels_path + "/" + kernel_path.stem + kernel_path.suffix) + + # Include the kernel file within the fwd + if kernel["fwd_include"]: + kernel_include_list.append( + kernel_dst_path / (kernel_src_path.stem + kernel_src_path.suffix)) if self.config_template != "": path_to_definition = f"{self.config_path}/{self.attributes['name']}.{self.config_extension}" -- GitLab From a64e9da8cbd2378a21fc46fb60f4520d9036be26 Mon Sep 17 00:00:00 2001 From: Axel Farrugia <axel.farrugia@cea.fr> Date: Fri, 21 Mar 2025 10:46:03 +0100 Subject: [PATCH 9/9] [Chore](Exports) Add SAVE_OUTPUTS and AIDGE_CMP flags on top of fwd file --- aidge_core/export_utils/templates/forward.jinja | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/aidge_core/export_utils/templates/forward.jinja b/aidge_core/export_utils/templates/forward.jinja index fde4b2a13..e054c3489 100644 --- a/aidge_core/export_utils/templates/forward.jinja +++ b/aidge_core/export_utils/templates/forward.jinja @@ -1,6 +1,9 @@ #include <stdint.h> +#define SAVE_OUTPUTS false // Save the feature maps into files (Not compatible with every export) +#define AIDGE_CMP false // Compare export and aidge feature maps (Not compatible with every export) + #ifdef SAVE_OUTPUTS #include <sys/types.h> #include <sys/stat.h> @@ -30,7 +33,6 @@ void {{ func_name }} ( {{ outputs_dtype[o] }}** {{ outputs_name[o] }}_ptr{% if not loop.last %}, {% endif %} {%- endfor -%}) { - {%- for action in actions %} {{ action }} {%- endfor %} -- GitLab