From a449cf97dbf218b860329d5440168335e66ac963 Mon Sep 17 00:00:00 2001
From: cmoineau <cyril.moineau@cea.fr>
Date: Fri, 26 Jul 2024 06:32:04 +0000
Subject: [PATCH] Update aidge_export to new export_node + aidge_export ->
 serialize_to_cpp

---
 aidge_core/__init__.py                        |  2 +-
 aidge_core/aidge_export_aidge/__init__.py     |  2 +-
 aidge_core/aidge_export_aidge/export.py       | 33 ++++----
 .../operator_export/conv.py                   | 58 +++++++------
 .../aidge_export_aidge/operator_export/fc.py  | 75 +++++++++--------
 .../operator_export/maxpooling.py             | 59 ++++++++------
 .../operator_export/producer.py               | 81 +++++++++++--------
 .../operator_export/relu.py                   | 38 +++++----
 .../aidge_export_aidge/operator_export/sub.py | 38 +++++----
 aidge_core/aidge_export_aidge/registry.py     |  6 ++
 .../templates/attributes/conv.jinja           | 16 ++--
 .../templates/attributes/fc.jinja             |  4 +-
 .../templates/attributes/maxpooling.jinja     | 10 +--
 .../aidge_export_aidge/templates/dnn.jinja    |  2 +-
 .../templates/graph_ctor/_set_input.jinja     |  6 +-
 .../templates/graph_ctor/conv.jinja           |  6 +-
 .../templates/graph_ctor/maxpooling.jinja     |  4 +-
 .../templates/parameter.jinja                 |  2 +-
 aidge_core/export_utils/__init__.py           |  2 +-
 aidge_core/export_utils/export_registry.py    |  5 +-
 aidge_core/export_utils/node_export.py        | 31 ++++---
 aidge_core/export_utils/scheduler_export.py   |  2 +-
 22 files changed, 272 insertions(+), 210 deletions(-)
 create mode 100644 aidge_core/aidge_export_aidge/registry.py

diff --git a/aidge_core/__init__.py b/aidge_core/__init__.py
index 00556a025..f677ff73f 100644
--- a/aidge_core/__init__.py
+++ b/aidge_core/__init__.py
@@ -12,4 +12,4 @@ from aidge_core.aidge_core import * # import so generated by PyBind
 import aidge_core.export_utils
 
 import aidge_core.utils
-import aidge_core.aidge_export_aidge
+from aidge_core.aidge_export_aidge import serialize_to_cpp
diff --git a/aidge_core/aidge_export_aidge/__init__.py b/aidge_core/aidge_export_aidge/__init__.py
index c5d6f96b3..9f042cdbc 100644
--- a/aidge_core/aidge_export_aidge/__init__.py
+++ b/aidge_core/aidge_export_aidge/__init__.py
@@ -5,4 +5,4 @@ FILE = Path(__file__).resolve()
 ROOT_EXPORT = FILE.parents[0]
 
 from .operator_export import *
-from .export import export
+from .export import serialize_to_cpp
diff --git a/aidge_core/aidge_export_aidge/export.py b/aidge_core/aidge_export_aidge/export.py
index a5b9df0c8..cb5aa3ef2 100644
--- a/aidge_core/aidge_export_aidge/export.py
+++ b/aidge_core/aidge_export_aidge/export.py
@@ -2,15 +2,14 @@ import aidge_core
 import shutil
 import os
 from pathlib import Path
-from .utils import supported_operators, OPERATORS_REGISTRY
-from . import ROOT_EXPORT
 
+import aidge_core.export_utils
+from . import ROOT_EXPORT
+from aidge_core.aidge_export_aidge.registry import ExportSerialize
 
 from aidge_core.export_utils  import ExportNode, generate_file
 
-
-
-def export(export_folder: str,
+def serialize_to_cpp(export_folder: str,
            graph_view: aidge_core.GraphView,
            enable_python_binding: bool = True,
            ):
@@ -59,7 +58,6 @@ def export(export_folder: str,
     open_nodes = list(graph_view.get_input_nodes())
     # List of Aidge nodes already explored
     closed_nodes = []
-
     while open_nodes:
         node = open_nodes.pop(0)
         if node in closed_nodes:
@@ -81,21 +79,22 @@ def export(export_folder: str,
         # Next nodes to treat are children of current node
         open_nodes += list(node.get_children())
 
-        if node.type() in supported_operators():
-            set_operator.add(node.type())
-            op = OPERATORS_REGISTRY[node.type()](node)
+        if not ExportSerialize.exportable(node):
+            #raise RuntimeError
+            print(f"Node {node.name()} (of type [{node.type()}]) is not exportable !")
+        op = ExportSerialize.get_export_node(node)(node)
+        set_operator.add(node.type())
 
-            # TODO: list_configs and list_actions don't need to be passed by argument
-            # Export the configuration
-            list_configs = op.export(export_folder_path, list_configs)
+        # TODO: list_configs and list_actions don't need to be passed by argument
+        # Export the configuration
+        list_configs += op.export(export_folder_path)
 
-            # Add forward kernel
-            list_actions = op.forward(list_actions)
-        else:
-            raise RuntimeError(f"Operator: {node.type()} is not supported")
+        # Add forward kernel
+        list_actions += op.forward()
         closed_nodes.append(node)
+
     # Generate full dnn.cpp
-    aidge_core.generate_file(
+    aidge_core.export_utils.generate_file(
         export_folder_path / "src/dnn.cpp",
         ROOT_EXPORT / "templates/dnn.jinja",
         headers=list_configs,
diff --git a/aidge_core/aidge_export_aidge/operator_export/conv.py b/aidge_core/aidge_export_aidge/operator_export/conv.py
index ee38fe72e..1b97d0b41 100644
--- a/aidge_core/aidge_export_aidge/operator_export/conv.py
+++ b/aidge_core/aidge_export_aidge/operator_export/conv.py
@@ -1,31 +1,41 @@
-from aidge_core.aidge_export_aidge.utils import operator_register, parse_node_input
+from aidge_core.aidge_export_aidge.registry import ExportSerialize
 from aidge_core.aidge_export_aidge import ROOT_EXPORT
-from aidge_core.export_utils import ExportNode, generate_file, generate_str
-from pathlib import Path
+from aidge_core.export_utils import ExportNodeCpp, operator_register
 
-@operator_register("Conv")
-class Conv(ExportNode):
+@operator_register(ExportSerialize, "Conv")
+class Conv(ExportNodeCpp):
     def __init__(self, node):
         super().__init__(node)
+        self.config_template = str(
+            ROOT_EXPORT / "templates/attributes/conv.jinja")
+        self.forward_template = str(
+            ROOT_EXPORT /"templates/graph_ctor/conv.jinja")
+        self.include_list = []
+        self.kernels_to_copy = []
+        self.config_path = "include/parameters"
+        self.config_extension = "hpp"
+    @classmethod
+    def exportable(cls, node):
+        return True
 
-    def export(self, export_folder:Path, list_configs:list):
-        include_path = f"attributes/{self.name}.hpp"
-        filepath = export_folder / f"include/{include_path}"
+    # def export(self, export_folder:Path, list_configs:list):
+    #     include_path = f"attributes/{self.name}.hpp"
+    #     filepath = export_folder / f"include/{include_path}"
 
-        generate_file(
-            filepath,
-            ROOT_EXPORT / "templates/attributes/conv.jinja",
-            name=self.name,
-            **self.attributes
-        )
-        list_configs.append(include_path)
-        return list_configs
+    #     generate_file(
+    #         filepath,
+    #         ROOT_EXPORT / "templates/attributes/conv.jinja",
+    #         name=self.name,
+    #         **self.attributes
+    #     )
+    #     list_configs.append(include_path)
+    #     return list_configs
 
-    def forward(self, list_actions:list):
-        list_actions.append(generate_str(
-            ROOT_EXPORT /"templates/graph_ctor/conv.jinja",
-            name=self.name,
-            inputs=parse_node_input(self.node.inputs()),
-            **self.attributes
-        ))
-        return list_actions
+    # def forward(self, list_actions:list):
+    #     list_actions.append(generate_str(
+    #         ROOT_EXPORT /"templates/graph_ctor/conv.jinja",
+    #         name=self.name,
+    #         inputs=parse_node_input(self.node.inputs()),
+    #         **self.attributes
+    #     ))
+    #     return list_actions
diff --git a/aidge_core/aidge_export_aidge/operator_export/fc.py b/aidge_core/aidge_export_aidge/operator_export/fc.py
index c72fe7648..8161eada9 100644
--- a/aidge_core/aidge_export_aidge/operator_export/fc.py
+++ b/aidge_core/aidge_export_aidge/operator_export/fc.py
@@ -1,37 +1,48 @@
-from aidge_core.aidge_export_aidge.utils import operator_register,parse_node_input
 from aidge_core.aidge_export_aidge import ROOT_EXPORT
-from aidge_core.export_utils import ExportNode, generate_file, generate_str
+from aidge_core.aidge_export_aidge.registry import ExportSerialize
+
+from aidge_core.export_utils import ExportNodeCpp, operator_register
 from pathlib import Path
 
-@operator_register("FC")
-class FC(ExportNode):
+@operator_register(ExportSerialize, "FC")
+class FC(ExportNodeCpp):
     def __init__(self, node):
         super().__init__(node)
-
-
-    def export(self, export_folder:Path, list_configs:list):
-
-
-        include_path = f"attributes/{self.name}.hpp"
-        filepath = export_folder / f"include/{include_path}"
-
-
-        generate_file(
-            filepath,
-            ROOT_EXPORT / "templates/attributes/fc.jinja",
-            name=self.name,
-            InChannels=self.inputs_dims[1][1],
-            OutChannels=self.operator.out_channels(),
-            **self.attributes
-        )
-        list_configs.append(include_path)
-        return list_configs
-
-    def forward(self, list_actions:list):
-        list_actions.append(generate_str(
-            ROOT_EXPORT / "templates/graph_ctor/fc.jinja",
-            name=self.name,
-            inputs=parse_node_input(self.node.inputs()),
-            **self.attributes
-        ))
-        return list_actions
+        self.config_template = str(
+            ROOT_EXPORT / "templates/attributes/fc.jinja")
+        self.forward_template = str(
+            ROOT_EXPORT / "templates/graph_ctor/fc.jinja")
+        self.include_list = []
+        self.kernels_to_copy = []
+        self.config_path = "include/parameters"
+        self.config_extension = "hpp"
+    @classmethod
+    def exportable(cls, node):
+        return True
+
+    # def export(self, export_folder:Path, list_configs:list):
+
+
+    #     include_path = f"attributes/{self.name}.hpp"
+    #     filepath = export_folder / f"include/{include_path}"
+
+
+    #     generate_file(
+    #         filepath,
+    #         ROOT_EXPORT / "templates/attributes/fc.jinja",
+    #         name=self.name,
+    #         InChannels=self.inputs_dims[1][1],
+    #         OutChannels=self.operator.out_channels(),
+    #         **self.attributes
+    #     )
+    #     list_configs.append(include_path)
+    #     return list_configs
+
+    # def forward(self, list_actions:list):
+    #     list_actions.append(generate_str(
+    #         ROOT_EXPORT / "templates/graph_ctor/fc.jinja",
+    #         name=self.name,
+    #         inputs=parse_node_input(self.node.inputs()),
+    #         **self.attributes
+    #     ))
+    #     return list_actions
diff --git a/aidge_core/aidge_export_aidge/operator_export/maxpooling.py b/aidge_core/aidge_export_aidge/operator_export/maxpooling.py
index ef996e6e6..571c72a01 100644
--- a/aidge_core/aidge_export_aidge/operator_export/maxpooling.py
+++ b/aidge_core/aidge_export_aidge/operator_export/maxpooling.py
@@ -1,32 +1,41 @@
-from aidge_core.aidge_export_aidge.utils import operator_register, parse_node_input
+from aidge_core.aidge_export_aidge.registry import ExportSerialize
 from aidge_core.aidge_export_aidge import ROOT_EXPORT
-from aidge_core.export_utils import ExportNode, generate_file, generate_str
-from pathlib import Path
+from aidge_core.export_utils import ExportNodeCpp, operator_register
 
-@operator_register("MaxPooling")
-class MaxPooling(ExportNode):
+@operator_register(ExportSerialize,"MaxPooling")
+class MaxPooling(ExportNodeCpp):
     def __init__(self, node):
         super().__init__(node)
+        self.config_template = str(
+            ROOT_EXPORT / "templates/attributes/maxpooling.jinja")
+        self.forward_template = str(
+            ROOT_EXPORT / "templates/graph_ctor/maxpooling.jinja")
+        self.include_list = []
+        self.kernels_to_copy = []
+        self.config_path = "include/parameters"
+        self.config_extension = "hpp"
+    @classmethod
+    def exportable(cls, node):
+        return True
 
+    # def export(self, export_folder:Path, list_configs:list):
+    #     include_path = f"attributes/{self.name}.hpp"
+    #     filepath = export_folder / f"include/{include_path}"
 
-    def export(self, export_folder:Path, list_configs:list):
-        include_path = f"attributes/{self.name}.hpp"
-        filepath = export_folder / f"include/{include_path}"
+    #     generate_file(
+    #         filepath,
+    #         ROOT_EXPORT / "templates/attributes/maxpooling.jinja",
+    #         name=self.name,
+    #         **self.attributes
+    #     )
+    #     list_configs.append(include_path)
+    #     return list_configs
 
-        generate_file(
-            filepath,
-            ROOT_EXPORT / "templates/attributes/maxpooling.jinja",
-            name=self.name,
-            **self.attributes
-        )
-        list_configs.append(include_path)
-        return list_configs
-
-    def forward(self, list_actions:list):
-        list_actions.append(generate_str(
-            ROOT_EXPORT / "templates/graph_ctor/maxpooling.jinja",
-            name=self.name,
-            inputs=parse_node_input(self.node.inputs()),
-            **self.attributes
-        ))
-        return list_actions
+    # def forward(self, list_actions:list):
+    #     list_actions.append(generate_str(
+    #         ROOT_EXPORT / "templates/graph_ctor/maxpooling.jinja",
+    #         name=self.name,
+    #         inputs=parse_node_input(self.node.inputs()),
+    #         **self.attributes
+    #     ))
+    #     return list_actions
diff --git a/aidge_core/aidge_export_aidge/operator_export/producer.py b/aidge_core/aidge_export_aidge/operator_export/producer.py
index 3886cffa0..c6ace522f 100644
--- a/aidge_core/aidge_export_aidge/operator_export/producer.py
+++ b/aidge_core/aidge_export_aidge/operator_export/producer.py
@@ -1,14 +1,11 @@
-from aidge_core.aidge_export_aidge.utils import operator_register
-from aidge_core.export_utils.data_conversion import aidge2c
-
 from aidge_core.aidge_export_aidge import ROOT_EXPORT
-from aidge_core.export_utils import ExportNode, generate_file, generate_str
+from aidge_core.aidge_export_aidge.registry import ExportSerialize
+from aidge_core.export_utils import ExportNodeCpp, operator_register
 import numpy as np
-from pathlib import Path
 
 
-@operator_register("Producer")
-class Producer(ExportNode):
+@operator_register(ExportSerialize, "Producer")
+class Producer(ExportNodeCpp):
     """
     If there is a standardization of the export operators
     then this class should be just a inheritance of ProducerCPP
@@ -16,33 +13,47 @@ class Producer(ExportNode):
     def __init__(self, node):
         super().__init__(node)
         child, in_idx = self.node.output(0)[0]
-        self.tensor_name = f"{child.name()}_{in_idx}"
+
         self.values = np.array(self.operator.get_output(0))
 
-    def export(self, export_folder:Path, list_configs:list):
-        assert(len(self.node.output(0)) == 1)
-
-        include_path = f"parameters/{self.tensor_name}.hpp"
-        filepath = export_folder / f"include/{include_path}"
-
-        aidge_tensor = self.operator.get_output(0)
-        datatype = aidge2c(aidge_tensor.dtype())
-        generate_file(
-            filepath,
-            ROOT_EXPORT / "templates/parameter.jinja",
-            dims = aidge_tensor.dims(),
-            data_t = datatype,
-            name = self.tensor_name,
-            values = str(aidge_tensor)
-        )
-        list_configs.append(include_path)
-        return list_configs
-
-    def forward(self, list_actions:list):
-        list_actions.append(generate_str(
-            ROOT_EXPORT / "templates/graph_ctor/producer.jinja",
-            name=self.name,
-            tensor_name=self.tensor_name,
-            **self.attributes
-        ))
-        return list_actions
+        self.config_template = str(
+            ROOT_EXPORT / "templates/parameter.jinja")
+        self.forward_template = str(
+            ROOT_EXPORT / "templates/graph_ctor/producer.jinja")
+        self.attributes["tensor_name"] = f"{child.name()}_{in_idx}"
+        self.attributes["values"] = str(self.operator.get_output(0))
+        self.include_list = []
+        self.kernels_to_copy = []
+        self.config_path = "include/parameters"
+        self.config_extension = "hpp"
+    @classmethod
+    def exportable(cls, node):
+        return True
+
+    # def export(self, export_folder:Path, list_configs:list):
+    #     assert(len(self.node.output(0)) == 1)
+
+    #     include_path = f"parameters/{self.tensor_name}.hpp"
+    #     filepath = export_folder / f"include/{include_path}"
+
+    #     aidge_tensor = self.operator.get_output(0)
+    #     datatype = aidge2c(aidge_tensor.dtype())
+    #     generate_file(
+    #         filepath,
+    #         ROOT_EXPORT / "templates/parameter.jinja",
+    #         dims = aidge_tensor.dims(),
+    #         data_t = datatype,
+    #         name = self.tensor_name,
+    #         values = str(aidge_tensor)
+    #     )
+    #     list_configs.append(include_path)
+    #     return list_configs
+
+    # def forward(self, list_actions:list):
+    #     list_actions.append(generate_str(
+    #         ROOT_EXPORT / "templates/graph_ctor/producer.jinja",
+    #         name=self.name,
+    #         tensor_name=self.tensor_name,
+    #         **self.attributes
+    #     ))
+    #     return list_actions
diff --git a/aidge_core/aidge_export_aidge/operator_export/relu.py b/aidge_core/aidge_export_aidge/operator_export/relu.py
index 21b368dfa..8012b2d04 100644
--- a/aidge_core/aidge_export_aidge/operator_export/relu.py
+++ b/aidge_core/aidge_export_aidge/operator_export/relu.py
@@ -1,21 +1,27 @@
-from aidge_core.aidge_export_aidge.utils import operator_register, parse_node_input
-from aidge_core.export_utils  import ExportNode, generate_str
+from aidge_core.aidge_export_aidge.registry import ExportSerialize
 from aidge_core.aidge_export_aidge import ROOT_EXPORT
-from pathlib import Path
+from aidge_core.export_utils import ExportNodeCpp, operator_register
 
-@operator_register("ReLU")
-class ReLU(ExportNode):
+@operator_register(ExportSerialize, "ReLU")
+class ReLU(ExportNodeCpp):
     def __init__(self, node):
         super().__init__(node)
+        self.config_template = ""
+        self.forward_template = str(
+            ROOT_EXPORT / "templates/graph_ctor/relu.jinja")
+        self.include_list = []
+        self.kernels_to_copy = []
+    @classmethod
+    def exportable(cls, node):
+        return True
+    # def export(self, export_folder:Path, list_configs:list):
+    #     return list_configs
 
-    def export(self, export_folder:Path, list_configs:list):
-        return list_configs
-
-    def forward(self, list_actions:list):
-        list_actions.append(generate_str(
-            ROOT_EXPORT / "templates/graph_ctor/relu.jinja",
-            name=self.name,
-            inputs=parse_node_input(self.node.inputs()),
-            **self.attributes
-        ))
-        return list_actions
+    # def forward(self, list_actions:list):
+    #     list_actions.append(generate_str(
+    #         ROOT_EXPORT / "templates/graph_ctor/relu.jinja",
+    #         name=self.name,
+    #         inputs=parse_node_input(self.node.inputs()),
+    #         **self.attributes
+    #     ))
+    #     return list_actions
diff --git a/aidge_core/aidge_export_aidge/operator_export/sub.py b/aidge_core/aidge_export_aidge/operator_export/sub.py
index 24315c921..80a96c7ee 100644
--- a/aidge_core/aidge_export_aidge/operator_export/sub.py
+++ b/aidge_core/aidge_export_aidge/operator_export/sub.py
@@ -1,21 +1,29 @@
-from aidge_core.aidge_export_aidge.utils import operator_register, parse_node_input
-from aidge_core.export_utils  import ExportNode, generate_str
+from aidge_core.aidge_export_aidge.registry import ExportSerialize
 from aidge_core.aidge_export_aidge import ROOT_EXPORT
-from pathlib import Path
+from aidge_core.export_utils import ExportNodeCpp, operator_register
 
-@operator_register("Sub")
-class Sub(ExportNode):
+@operator_register(ExportSerialize, "Sub")
+class Sub(ExportNodeCpp):
     def __init__(self, node):
         super().__init__(node)
+        self.config_template = ""
+        self.forward_template = str(
+            ROOT_EXPORT / "templates/graph_ctor/sub.jinja")
+        self.include_list = []
+        self.kernels_to_copy = []
 
-    def export(self, export_folder:Path, list_configs:list):
-        return list_configs
+    @classmethod
+    def exportable(cls, node):
+        return True
 
-    def forward(self, list_actions:list):
-        list_actions.append(generate_str(
-            ROOT_EXPORT / "templates/graph_ctor/sub.jinja",
-            name=self.name,
-            inputs=parse_node_input(self.node.inputs()),
-            **self.attributes
-        ))
-        return list_actions
+    # def export(self, export_folder:Path, list_configs:list):
+    #     return list_configs
+
+    # def forward(self, list_actions:list):
+    #     list_actions.append(generate_str(
+    #         ROOT_EXPORT / "templates/graph_ctor/sub.jinja",
+    #         name=self.name,
+    #         inputs=parse_node_input(self.node.inputs()),
+    #         **self.attributes
+    #     ))
+    #     return list_actions
diff --git a/aidge_core/aidge_export_aidge/registry.py b/aidge_core/aidge_export_aidge/registry.py
new file mode 100644
index 000000000..477dc583d
--- /dev/null
+++ b/aidge_core/aidge_export_aidge/registry.py
@@ -0,0 +1,6 @@
+from aidge_core.export_utils import ExportLib
+from . import ROOT_EXPORT
+
+class ExportSerialize(ExportLib):
+    name="export_serialize"
+
diff --git a/aidge_core/aidge_export_aidge/templates/attributes/conv.jinja b/aidge_core/aidge_export_aidge/templates/attributes/conv.jinja
index 48d07e8db..58c52abec 100644
--- a/aidge_core/aidge_export_aidge/templates/attributes/conv.jinja
+++ b/aidge_core/aidge_export_aidge/templates/attributes/conv.jinja
@@ -1,17 +1,17 @@
 #ifndef EXPORT_ATTRIBUTES_{{name|upper}}_H
 #define EXPORT_ATTRIBUTES_{{name|upper}}_H
 
-#define _{{name|upper}}_IN_CHANNELS  {{InChannels}}
-#define _{{name|upper}}_OUT_CHANNELS {{OutChannels}}
+#define _{{name|upper}}_IN_CHANNELS  {{in_chan[0]}}
+#define _{{name|upper}}_OUT_CHANNELS {{out_chan[0]}}
 
-{% for i in range(KernelDims|length) %}
-#define _{{name|upper}}_KERNEL_{{i}} {{KernelDims[i]}}
+{% for i in range(kernel_dims|length) %}
+#define _{{name|upper}}_KERNEL_{{i}} {{kernel_dims[i]}}
 {%- endfor %}
-{% for i in range(StrideDims|length) %}
-#define _{{name|upper}}_STRIDE_{{i}} {{StrideDims[i]}}
+{% for i in range(stride_dims|length) %}
+#define _{{name|upper}}_STRIDE_{{i}} {{stride_dims[i]}}
 {%- endfor %}
-{% for i in range(DilationDims|length) %}
-#define _{{name|upper}}_DILATION_{{i}} {{DilationDims[i]}}
+{% for i in range(dilation_dims|length) %}
+#define _{{name|upper}}_DILATION_{{i}} {{dilation_dims[i]}}
 {%- endfor %}
 
 #endif /* EXPORT_ATTRIBUTES_{{name|upper}}_H */
diff --git a/aidge_core/aidge_export_aidge/templates/attributes/fc.jinja b/aidge_core/aidge_export_aidge/templates/attributes/fc.jinja
index e292f9b61..32f4d0051 100644
--- a/aidge_core/aidge_export_aidge/templates/attributes/fc.jinja
+++ b/aidge_core/aidge_export_aidge/templates/attributes/fc.jinja
@@ -1,7 +1,7 @@
 #ifndef EXPORT_ATTRIBUTES_{{name|upper}}_H
 #define EXPORT_ATTRIBUTES_{{name|upper}}_H
 
-#define _{{name|upper}}_IN_CHANNELS  {{InChannels}}
-#define _{{name|upper}}_OUT_CHANNELS {{OutChannels}}
+#define _{{name|upper}}_IN_CHANNELS  {{in_chan[0]}}
+#define _{{name|upper}}_OUT_CHANNELS {{out_chan[0]}}
 
 #endif /* EXPORT_ATTRIBUTES_{{name|upper}}_H */
diff --git a/aidge_core/aidge_export_aidge/templates/attributes/maxpooling.jinja b/aidge_core/aidge_export_aidge/templates/attributes/maxpooling.jinja
index d258f580e..96de14b01 100644
--- a/aidge_core/aidge_export_aidge/templates/attributes/maxpooling.jinja
+++ b/aidge_core/aidge_export_aidge/templates/attributes/maxpooling.jinja
@@ -1,13 +1,13 @@
 #ifndef EXPORT_ATTRIBUTES_{{name|upper}}_H
 #define EXPORT_ATTRIBUTES_{{name|upper}}_H
 
-{% for i in range(KernelDims|length) %}
-#define _{{name|upper}}_KERNEL_{{i}} {{KernelDims[i]}}
+{% for i in range(kernel_dims|length) %}
+#define _{{name|upper}}_KERNEL_{{i}} {{kernel_dims[i]}}
 {%- endfor %}
-{% for i in range(StrideDims|length) %}
-#define _{{name|upper}}_STRIDE_{{i}} {{StrideDims[i]}}
+{% for i in range(stride_dims|length) %}
+#define _{{name|upper}}_STRIDE_{{i}} {{stride_dims[i]}}
 {%- endfor %}
 
-#define _{{name|upper}}_CEIL_MODE {{CeilMode|int}}
+#define _{{name|upper}}_CEIL_MODE {{ceil_mode|int}}
 
 #endif /* EXPORT_ATTRIBUTES_{{name|upper}}_H */
diff --git a/aidge_core/aidge_export_aidge/templates/dnn.jinja b/aidge_core/aidge_export_aidge/templates/dnn.jinja
index 5da46b2d8..bb8faff4a 100644
--- a/aidge_core/aidge_export_aidge/templates/dnn.jinja
+++ b/aidge_core/aidge_export_aidge/templates/dnn.jinja
@@ -17,7 +17,7 @@
 
 /*** OPERATOR ATTRIBUTES & PARAMETERS ***/
 {%- for header in headers %}
-#include "{{ header }}"
+#include "{{ header | replace('include/', '') }}"
 {%- endfor %}
 
 /*** HEADER ***/
diff --git a/aidge_core/aidge_export_aidge/templates/graph_ctor/_set_input.jinja b/aidge_core/aidge_export_aidge/templates/graph_ctor/_set_input.jinja
index 8e841ea2a..d9f59a946 100644
--- a/aidge_core/aidge_export_aidge/templates/graph_ctor/_set_input.jinja
+++ b/aidge_core/aidge_export_aidge/templates/graph_ctor/_set_input.jinja
@@ -1,7 +1,7 @@
 {# NOTE: Trying a shorter notation like {%- for input in inputs if input[0] %}
 will mess up loop.index as the input set up at None will not increment ! #}
-{%- for input in inputs %}
-{%- if input[0] %}
-{{input[0]}}->addChild({{name}}, {{input[1]}}, {{loop.index - 1}}); {# NOTE: loop.index begin at 1 #}
+{%- for input_node, out_id in node.inputs() %}
+{%- if input_node %}
+{{input_node.name()}}->addChild({{name}}, {{out_id}}, {{loop.index - 1}}); {# NOTE: loop.index begin at 1 #}
 {%- endif %}
 {%- endfor %}
diff --git a/aidge_core/aidge_export_aidge/templates/graph_ctor/conv.jinja b/aidge_core/aidge_export_aidge/templates/graph_ctor/conv.jinja
index a805f8065..bd4eed2d3 100644
--- a/aidge_core/aidge_export_aidge/templates/graph_ctor/conv.jinja
+++ b/aidge_core/aidge_export_aidge/templates/graph_ctor/conv.jinja
@@ -5,18 +5,18 @@ std::shared_ptr<Aidge::Node> {{name}} =
             _{{name|upper}}_IN_CHANNELS,
             _{{name|upper}}_OUT_CHANNELS,
             {
-            {%- for i in range(KernelDims|length) -%}
+            {%- for i in range(kernel_dims|length) -%}
                 _{{name|upper}}_KERNEL_{{i}}{%- if not loop.last %}, {% endif -%}
             {%- endfor -%}
             },
             "{{name}}",
             {
-            {%- for i in range(StrideDims|length) -%}
+            {%- for i in range(stride_dims|length) -%}
                 _{{name|upper}}_STRIDE_{{i}} {%- if not loop.last %}, {% endif -%}
             {%- endfor -%}
             },
             {
-            {%- for i in range(DilationDims|length) -%}
+            {%- for i in range(dilation_dims|length) -%}
                 _{{name|upper}}_DILATION_{{i}} {%- if not loop.last %}, {% endif -%}
             {%- endfor -%}
             }
diff --git a/aidge_core/aidge_export_aidge/templates/graph_ctor/maxpooling.jinja b/aidge_core/aidge_export_aidge/templates/graph_ctor/maxpooling.jinja
index c6587c128..ceb4784a0 100644
--- a/aidge_core/aidge_export_aidge/templates/graph_ctor/maxpooling.jinja
+++ b/aidge_core/aidge_export_aidge/templates/graph_ctor/maxpooling.jinja
@@ -3,13 +3,13 @@
 std::shared_ptr<Aidge::Node> {{name}} =
         Aidge::MaxPooling(
             {
-            {%- for i in range(KernelDims|length) -%}
+            {%- for i in range(kernel_dims|length) -%}
                 _{{name|upper}}_KERNEL_{{i}}{%- if not loop.last %}, {% endif -%}
             {%- endfor -%}
             },
             "{{name}}",
             {
-            {%- for i in range(StrideDims|length) -%}
+            {%- for i in range(stride_dims|length) -%}
                 _{{name|upper}}_STRIDE_{{i}} {%- if not loop.last %}, {% endif -%}
             {%- endfor -%}
             },
diff --git a/aidge_core/aidge_export_aidge/templates/parameter.jinja b/aidge_core/aidge_export_aidge/templates/parameter.jinja
index 11a407cc8..0ff9634d9 100644
--- a/aidge_core/aidge_export_aidge/templates/parameter.jinja
+++ b/aidge_core/aidge_export_aidge/templates/parameter.jinja
@@ -4,7 +4,7 @@
 #include <aidge/data/Tensor.hpp>
 #include <memory>
 
-std::shared_ptr<Aidge::Tensor> {{name}} = std::make_shared<Aidge::Tensor>(Aidge::Array{{dims|length}}D<{{data_t}}, {{ dims|join(", ") }}> {
+std::shared_ptr<Aidge::Tensor> {{tensor_name}} = std::make_shared<Aidge::Tensor>(Aidge::Array{{out_dims[0]|length}}D<{{out_cdtype[0]}}, {{ out_dims[0]|join(", ") }}> {
 {{ values }}
 });
 
diff --git a/aidge_core/export_utils/__init__.py b/aidge_core/export_utils/__init__.py
index 403036030..f23948081 100644
--- a/aidge_core/export_utils/__init__.py
+++ b/aidge_core/export_utils/__init__.py
@@ -1,4 +1,4 @@
 from .node_export import ExportNode, ExportNodeCpp
 from .code_generation import generate_file, generate_str, copy_file
 from .export_registry import ExportLib, operator_register
-from .scheduler_export import ExportScheduler
+from .scheduler_export import scheduler_export
diff --git a/aidge_core/export_utils/export_registry.py b/aidge_core/export_utils/export_registry.py
index 1d6dcde88..50699b484 100644
--- a/aidge_core/export_utils/export_registry.py
+++ b/aidge_core/export_utils/export_registry.py
@@ -26,9 +26,6 @@ class ExportLib(): # Should be abstract ?
     _language: LANGUAGE = None
     _compilo:str = None
 
-
-
-
     def __init__(self) -> None:
          raise RuntimeError("ExportLib should not be instanciated")
     @classmethod
@@ -63,7 +60,7 @@ class ExportLib(): # Should be abstract ?
         :rtype: ExportNode
         """
         if not cls.exportable(node):
-            raise ValueError(f"Node {node.type()} is not exportable by ExportLib {cls._name} !")
+            raise ValueError(f"Node {node.type()} is not exportable by ExportLib {cls.name} !")
         if len(cls._export_node_registry[node.type()]) != 1:
             raise RuntimeError("ExportLib registry doesn't support when multiple export node are available yet ...")
         else:
diff --git a/aidge_core/export_utils/node_export.py b/aidge_core/export_utils/node_export.py
index 581e9070b..79a3dd140 100644
--- a/aidge_core/export_utils/node_export.py
+++ b/aidge_core/export_utils/node_export.py
@@ -123,6 +123,7 @@ class ExportNode(ABC):
         # Attributes are auto fetched from aidge operators
         self.attributes = self.operator.attr.dict(
         ) if self.operator.attr is not None else {}
+        self.attributes["node"] = self.node
         self.attributes["name"] = self.node.name()
         self.attributes["nb_in"] = self.node.get_nb_inputs()
         self.attributes["nb_out"] = self.node.get_nb_outputs()
@@ -159,7 +160,7 @@ class ExportNode(ABC):
         # Producer don't have meminfo
         # TODO: document this attribute
         # true if node have meminfo else false
-        self.attributes["meminfo"] = mem_info or self.node.type() != "Producer"
+        self.attributes["meminfo"] = mem_info is not None and self.node.type() != "Producer"
         if self.attributes["meminfo"]:
             self.attributes["mem_info_size"] = [None] * self.attributes["nb_out"]
             self.attributes["mem_info_offset"] = [None] * self.attributes["nb_out"]
@@ -266,9 +267,12 @@ class ExportNodeCpp(ExportNode):
     # kernels are copied in str(export_folder / "include" / "kernels")
     # They are automatically added to the include list.
     kernels_to_copy: list = None
-    # Path where all the kernels are stored in the export (prefixed by export_root/include)
-    kernels_path: str = "kernels"
-
+    # 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"
     def export(self, export_folder: str):
         """Define how to export the node definition.
         """
@@ -277,25 +281,26 @@ class ExportNodeCpp(ExportNode):
         if self.include_list is None:
             raise ValueError("include_list have not been defined")
         if self.kernels_to_copy is None:
-            raise ValueError("required_kernels have not been defined")
+            raise ValueError("kernels_to_copy have not been defined")
 
         kernel_include_list = []
         for kernel in self.kernels_to_copy:
             kernel_path = Path(kernel)
             code_generation.copy_file(
                 kernel_path,
-                str(export_folder / "include" / self.kernels_path)
+                str(export_folder / self.kernels_path)
             )
             kernel_include_list.append(
                 self.kernels_path + "/" + kernel_path.stem + kernel_path.suffix)
-        path_to_definition = f"include/layers/{self.attributes['name']}.h"
-        code_generation.generate_file(
-            str(export_folder / path_to_definition),
-            self.config_template,
-            **self.attributes
-        )
 
-        kernel_include_list.append(path_to_definition)
+        if self.config_template != "":
+            path_to_definition = f"{self.config_path}/{self.attributes['name']}.{self.config_extension}"
+            code_generation.generate_file(
+                str(export_folder / path_to_definition),
+                self.config_template,
+                **self.attributes
+            )
+            kernel_include_list.append(path_to_definition)
 
         return self.include_list + kernel_include_list
 
diff --git a/aidge_core/export_utils/scheduler_export.py b/aidge_core/export_utils/scheduler_export.py
index c12f15ab7..5e44bb30d 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
 from typing import List, Tuple
 
 
-def export(scheduler, export_folder_path: str, export_lib: ExportLib = None, memory_manager=None, memory_manager_args=None) -> None:
+def scheduler_export(scheduler, export_folder_path: str, export_lib: ExportLib = None, memory_manager=None, memory_manager_args=None) -> None:
         graphview = scheduler.graph_view()
         export_folder = Path().absolute() / export_folder_path
 
-- 
GitLab