diff --git a/aidge_export_cpp/kernels/pad.hpp b/aidge_export_cpp/kernels/pad.hpp
index dc7629fc571ac722ed8d13937b454e96fcd59e21..158c9359c934f2735c12e47cbd186a4f30715554 100644
--- a/aidge_export_cpp/kernels/pad.hpp
+++ b/aidge_export_cpp/kernels/pad.hpp
@@ -2,10 +2,7 @@
 #define __AIDGE_EXPORT_CPP_KERNELS_PAD2D__
 
 #include "network/typedefs.hpp"
-#include "kernels/rescaling.hpp"
 #include "network/utils.hpp"
-#include "kernels/macs.hpp"
-#include "kernels/activation.hpp"
 
 // Todo add border value and border type (Reflect, Constant, Wrap...) and add the two missing pad value (bottom and right)
 
@@ -21,20 +18,20 @@ void convolution_forward(
     Output_T* __restrict outputs
     )
 {
-    const I *input = static_cast<const I *>(input_);
-    O *output = static_cast<O *>(output_);
+    const unsigned int oySize = CHANNELS_HEIGHT + PADDING_Y + PADDING_Y;
+    const unsigned int oxSize = CHANNELS_WIDTH + PADDING_X + PADDING_X;
 
-    const std::size_t oySize = CHANNELS_HEIGHT + PADDING_Y + PADDING_Y;
-    const std::size_t oxSize = CHANNELS_WIDTH + PADDING_X + PADDING_X;
-
-    for (std::uint32_t oy = 0; oy < oySize; ++oy) {
-        for (std::uint32_t ox = 0; ox < oxSize; ++ox) {
+    for (unsigned int oy = 0; oy < oySize; ++oy) {
+        for (unsigned int ox = 0; ox < oxSize; ++ox) {
             if (oy < PADDING_Y or oy >= CHANNELS_HEIGHT + PADDING_Y or ox < PADDING_X or ox >= CHANNELS_WIDTH + PADDING_X)
             {
                 outputs[oy * oySize + ox] = 0.0f;
             }
+            else
+            {
+                outputs[oy * oySize + ox] = inputs[(oy - PADDING_Y) * CHANNELS_HEIGHT + (ox - PADDING_X)];
+            }
 
-            outputs[oy * oySize + ox] = input[(oy - PADDING_Y) * CHANNELS_HEIGHT + (ox - PADDING_X)];
         }
     }
 }
diff --git a/aidge_export_cpp/kernels/pooling.hpp b/aidge_export_cpp/kernels/pooling.hpp
index 478b6a58aed45e2bce0ed1683ad113f9c7a8bffb..667e1a98cc3542cf598d223d59a767dccad6c651 100644
--- a/aidge_export_cpp/kernels/pooling.hpp
+++ b/aidge_export_cpp/kernels/pooling.hpp
@@ -7,7 +7,7 @@
 #include <stdexcept>
 
 
-template<int NB_CHANNELS, 
+template<int NB_CHANNELS,
          int CHANNELS_HEIGHT, int CHANNELS_WIDTH,
          int NB_OUTPUTS,
          int OUTPUTS_HEIGHT, int OUTPUTS_WIDTH,
@@ -17,7 +17,7 @@ template<int NB_CHANNELS,
          Pooling_T POOLING_TYPE,
          ActivationFunction_T ACTIVATION,
          typename Input_T, typename Output_T>
-__attribute__((always_inline)) inline 
+__attribute__((always_inline)) inline
 void pooling_forward(
     const Input_T* __restrict inputs,
     Output_T* __restrict outputs)
@@ -32,7 +32,7 @@ void pooling_forward(
             : max(PADDING_Y - (oy * STRIDE_Y), 0);
         const int syMax = (PADDING_Y == 0
                 && OUTPUTS_HEIGHT == OUTPUTS_HEIGHT_NOPAD) ? POOL_HEIGHT
-            : clamp(CHANNELS_HEIGHT + PADDING_Y - (oy * STRIDE_Y), 
+            : clamp(CHANNELS_HEIGHT + PADDING_Y - (oy * STRIDE_Y),
                     0, POOL_HEIGHT);
         const int iy = (oy * STRIDE_Y) - PADDING_Y;
 
@@ -45,7 +45,7 @@ void pooling_forward(
                 const int sxMax = (PADDING_X == 0
                         && OUTPUTS_WIDTH == OUTPUTS_WIDTH_NOPAD)
                             ? POOL_WIDTH
-                    : clamp(CHANNELS_WIDTH + PADDING_X - (ox * STRIDE_X), 
+                    : clamp(CHANNELS_WIDTH + PADDING_X - (ox * STRIDE_X),
                             0, POOL_WIDTH);
                 const int ix = (ox * STRIDE_X) - PADDING_X;
 
diff --git a/aidge_export_cpp/operators.py b/aidge_export_cpp/operators.py
index 0e3749a3592cce219f9ce8fe6888b42fea587ed1..c89236bf7b452c370d6dc6577b61a9e0b7aa9cdc 100644
--- a/aidge_export_cpp/operators.py
+++ b/aidge_export_cpp/operators.py
@@ -353,14 +353,10 @@ class BatchNorm2DCPP(ExportNodeCpp):
 class Concat(ExportNodeCpp):
     def __init__(self, node, mem_info):
         super().__init__(node, mem_info)
-
-        print(node.get_operator())
-        print(dir(node.get_operator()))
-        self.attributes["nb_in"] = node.get_operator().nb_inputs()
         self.attributes["axis"] = node.get_operator().attr.axis
 
-        self.config_template = str(ROOT / "templates" / "configuration" / "concat.jinja")
-        self.forward_template = str(ROOT / "templates" / "forward_call" / "concat.jinja")
+        self.config_template = str(ROOT / "templates" / "configuration" / "concat_config.jinja")
+        self.forward_template = str(ROOT / "templates" / "kernel_forward" / "concat_forward.jinja")
         self.include_list = []
         self.kernels_to_copy = [
             str(ROOT / "kernels" / "concat.hpp"),
diff --git a/aidge_export_cpp/templates/configuration/batchnorm_config.jinja b/aidge_export_cpp/templates/configuration/batchnorm_config.jinja
index bc01e3b964d3741548bb3249d88aa9034ecaa343..ae7ef5760a63689d11f6d7369e387b55b7cb3d15 100644
--- a/aidge_export_cpp/templates/configuration/batchnorm_config.jinja
+++ b/aidge_export_cpp/templates/configuration/batchnorm_config.jinja
@@ -1,6 +1,7 @@
 {#- For name header -#}
 #ifndef {{ name|upper }}_LAYER_H
 #define {{ name|upper }}_LAYER_H
+#include "kernels/rescaling.hpp"
 
 {# For layer configuration -#}
 {% include "./_def_io.jinja" %}
diff --git a/aidge_export_cpp/templates/configuration/concat.jinja b/aidge_export_cpp/templates/configuration/concat_config.jinja
similarity index 63%
rename from aidge_export_cpp/templates/configuration/concat.jinja
rename to aidge_export_cpp/templates/configuration/concat_config.jinja
index 8aa63156a2d890bbfb6f0c7ddce700917ccef83b..1a6637e9094c12fc04d47da4bddcee160f3c7a56 100644
--- a/aidge_export_cpp/templates/configuration/concat.jinja
+++ b/aidge_export_cpp/templates/configuration/concat_config.jinja
@@ -2,14 +2,15 @@
 #ifndef {{ name|upper }}_LAYER_H
 #define {{ name|upper }}_LAYER_H
 
+{% include "./_def_io.jinja" %}
 {% include "./_meminfo.jinja" %}
 
 // Attributes
 #define {{ name|upper }}_NB_INPUTS {{ nb_in }}
 #define {{ name|upper }}_AXIS {{ axis }}
 {%- for i in range(nb_in) %}
-#define {{ name|upper }}_INPUT_{{i}}_SIZE {{ in_chan[i] * in_height[i] * in_width[i] }}
+#define {{ name|upper }}_INPUT_{{i}}_SIZE {{ in_dims[i]|join('*') }}
 {%- endfor %}
-#define {{ name|upper }}_OUTPUT_SIZE {{ out_chan[0] * out_height[0] * out_width[0] }}
+#define {{ name|upper }}_OUTPUT_SIZE {{ out_dims[0]|join('*')}}
 
 #endif /* {{ name|upper }}_LAYER_H */
diff --git a/aidge_export_cpp/templates/kernel_forward/concat.jinja b/aidge_export_cpp/templates/kernel_forward/concat_forward.jinja
similarity index 86%
rename from aidge_export_cpp/templates/kernel_forward/concat.jinja
rename to aidge_export_cpp/templates/kernel_forward/concat_forward.jinja
index 46fe87e43c51c672b3d74bfbaabbb21aaac12ee7..a2f48e9b5aa563924a346eabfaec67b0c30ef38f 100644
--- a/aidge_export_cpp/templates/kernel_forward/concat.jinja
+++ b/aidge_export_cpp/templates/kernel_forward/concat_forward.jinja
@@ -1,6 +1,6 @@
 {% filter indent(width=4, first=False) %}
 {% include "./_mem_offset.jinja" %}
-float* {{ name|upper }}_INPUTS[] = {
+const float* {{ name|upper }}_INPUTS[] = {
     {%- for i in range(nb_in) -%}
         {{ in_name[i] }}{{ ", " if not loop.last else "" }}
     {%- endfor -%}
@@ -12,7 +12,7 @@ unsigned int {{ name|upper }}_SIZES[] = {
     {%- endfor -%}
 };
 
-aidge_concat<float, {{ nb_in }}> (
+concat_forward<float, {{ nb_in }}> (
     {{name|upper}}_AXIS,
     {{ name|upper }}_INPUTS,
     {{ name|upper }}_SIZES,
diff --git a/aidge_export_cpp/unit_tests/test_export.py b/aidge_export_cpp/unit_tests/test_export.py
index 20421adbe3ab90f1eba1a4df03ab141c21dc0c2d..273c9b4b0481771a2f90a8a6818787e37d28efd4 100644
--- a/aidge_export_cpp/unit_tests/test_export.py
+++ b/aidge_export_cpp/unit_tests/test_export.py
@@ -3,6 +3,8 @@ import aidge_core
 import aidge_backend_cpu
 import aidge_export_cpp
 import numpy as np
+import operator
+from functools import reduce
 
 import subprocess
 import re
@@ -31,19 +33,8 @@ def initFiller(model):
                 aidge_core.constant_filler(value, 0.01)
             else:
                 pass
-import math
-
-def normalize_random_tensor(randList):
-    for index in np.ndindex(randList.shape):
-        randList[index] = (math.floor(randList[index] * 21) - 10) / 10
-
-    return aidge_core.Tensor(randList.astype(np.float32))
-
-import numpy as np
-import operator
-from functools import reduce
 
-def np_init(shape, dtype=np.float32):
+def _np_init(shape, dtype=np.float32):
     """
     Generates a NumPy array with the given shape, filled with random values between -1 and 1
     with a step of 0.1.
@@ -56,71 +47,18 @@ def np_init(shape, dtype=np.float32):
     data = (np.random.randint(0, 21, size=total_elements) - 10) / 10.0
     return data.reshape(shape).astype(dtype)
 
-def unit_test_export(graph_view, op_name, in_dims):
-    # Initialize parameters (weights and biases)
-
-    graph_view.compile("cpu", aidge_core.dtype.float32, dims=in_dims)
-
-    for node in graph_view.get_nodes():
-        if node.type() == "Producer":
-            prod_op = node.get_operator()
-            value = prod_op.get_output(0)
-
-            # rand_tensor = aidge_core.Tensor(np_init(value.dims()))
-            # rand_tensor.set_backend(value.backend())
-            # value = rand_tensor
-
-            print(value)
-
-            aidge_core.constant_filler(value, 0.01)
-
-
-    scheduler = aidge_core.SequentialScheduler(graph_view)
-
-    in_tensor = [aidge_core.Tensor(np_init(in_dim)) for in_dim in in_dims]
-
-    scheduler.forward(data=in_tensor)
-
-    export_folder = op_name + "_temp_test"
-    # Export the model in C++ standalone
-    aidge_core.export_utils.scheduler_export(
-            scheduler,
-            export_folder,
-            aidge_export_cpp.ExportLibCpp,
-            memory_manager=aidge_core.mem_info.generate_optimized_memory_info,
-            memory_manager_args={"stats_folder": f"{export_folder}/stats", "wrapping": False }
-    )
-    aidge_core.export_utils.generate_main_compare_cpp(export_folder, graph_view)
-    print("COMPILATION")
-
-    try:
-        for std_line in run_command(["make"], cwd=export_folder):
-            print(std_line, end="")
-    except subprocess.CalledProcessError as e:
-        print(f"An error occurred: {e}\nFailed to generate export.")
-        raise SystemExit(1)
-    print("RUN EXPORT")
-    pattern = r"Number of equal outputs: (\d+) / (\d+)"
-    comparison_matched = False
-    result = False
-    try:
-        for std_line in run_command(["./bin/run_export"], cwd=export_folder):
-            print(std_line, end="")
-            matches = re.findall(pattern, std_line)
-            if matches:
-                if comparison_matched:
-                    raise RuntimeError("Two comparison matched found!")
-                else:
-                    expected, infered = map(int, matches[0])
-                    result = (expected == infered)
-                comparison_matched = True
-    except subprocess.CalledProcessError as e:
-        print(f"An error occurred: {e}\nFailed to run export for comparison.")
-        raise SystemExit(1)
-    if not comparison_matched:
-        raise RuntimeError("No comparison matched found!")
+def _np_init_ones(shape, default_value=0.01, dtype=np.float32):
+    """
+    Generates a NumPy array with the given shape, filled with random values between -1 and 1
+    with a step of 0.1.
 
-    return result
+    :param shape: Tuple of dimensions for the array
+    :param dtype: Data type of the output array (default: np.float32)
+    :return: A NumPy array with the given shape and dtype
+    """
+    total_elements = reduce(operator.mul, shape, 1)
+    data = np.ones(total_elements) * default_value
+    return data.reshape(shape).astype(dtype)
 
 
 class test_operator_export(unittest.TestCase):
@@ -133,7 +71,7 @@ class test_operator_export(unittest.TestCase):
     def tearDown(self):
         pass
 
-    def unit_test_export(self, graph_view, op_name, in_dims):
+    def unit_test_export(self, graph_view, op_name, in_dims, random_inputs=True, random_weights=True, default_value=0.01):
         """
         TODO:
         * Handle multiple dataformat
@@ -146,9 +84,27 @@ class test_operator_export(unittest.TestCase):
         4- Retrieve standard output and using regex to now if the results are the same
         """
         graph_view.compile("cpu", aidge_core.dtype.float32, dims=in_dims)
+
+        for node in graph_view.get_nodes():
+            if node.type() == "Producer":
+                prod_op = node.get_operator()
+                value = prod_op.get_output(0)
+
+                if (random_weights):
+                    tensor = aidge_core.Tensor(_np_init(value.dims()))
+
+                    node.get_operator().set_output(0, tensor)
+                else:
+                    aidge_core.constant_filler(value, default_value)
+
+
         scheduler = aidge_core.SequentialScheduler(graph_view)
 
-        in_tensor = [aidge_core.Tensor(np.random.random(in_dim).astype(np.float32)) for in_dim in in_dims]
+        if (random_inputs):
+            in_tensor = [aidge_core.Tensor(_np_init(in_dim)) for in_dim in in_dims]
+        else:
+            in_tensor = [aidge_core.Tensor(_np_init_ones(in_dim, default_value)) for in_dim in in_dims]
+
         scheduler.forward(data=in_tensor)
 
         # Note the convention ``<op_name>_test`` is useful for gitignore to avoid pushing generated export by accident.
@@ -208,7 +164,7 @@ class test_operator_export(unittest.TestCase):
             aidge_core.Softmax(axis=1, name="sf0")
         ])
 
-        self.assertTrue(unit_test_export(model, "Softmax", [[1, 10]]))
+        self.unit_test_export(model, "Softmax", [[1, 10]])
 
     @unittest.skip("Currently this test is failing")
     def test_export_FC_image_in(self):
@@ -226,7 +182,7 @@ class test_operator_export(unittest.TestCase):
             aidge_core.ReLU(name="relu0")
         ])
 
-        self.assertTrue(unit_test_export(model, "ReLU", [[1, 10]]))
+        self.unit_test_export(model, "ReLU", [[1, 10]])
 
     def test_export_add(self):
         print("Add")
@@ -235,7 +191,7 @@ class test_operator_export(unittest.TestCase):
             aidge_core.Add(name="add")
         ])
 
-        self.assertTrue(unit_test_export(model, "Add", [[1, 5, 5]]))
+        self.unit_test_export(model, "Add", [[1, 5, 5]])
 
     def test_export_sub(self):
         print("Sub")
@@ -244,7 +200,7 @@ class test_operator_export(unittest.TestCase):
             aidge_core.Sub(name="sub")
         ])
 
-        self.assertTrue(unit_test_export(model, "Sub", [[1, 5, 5]]))
+        self.unit_test_export(model, "Sub", [[1, 5, 5]])
 
     def test_export_mul(self):
         print("Mul")
@@ -253,7 +209,16 @@ class test_operator_export(unittest.TestCase):
             aidge_core.Mul(name="mul")
         ])
 
-        self.assertTrue(unit_test_export(model, "Mul", [[1, 5, 5]]))
+        self.unit_test_export(model, "Mul", [[1, 5, 5]])
+
+    def test_export_concat(self):
+        print("Concat")
+        model = aidge_core.sequential([
+            aidge_core.Producer([1, 5, 5], name="producer"),
+            aidge_core.Concat(nb_inputs=2, axis=1, name="concat")
+        ])
+
+        self.unit_test_export(model, "Concat", [[1, 5, 5]])
 
     def test_export_conv2D(self):
         print("Conv2D")
@@ -261,7 +226,7 @@ class test_operator_export(unittest.TestCase):
             aidge_core.Conv2D(in_channels=3, out_channels=3, kernel_dims=(3, 3), name="conv")
         ])
 
-        self.assertTrue(unit_test_export(model, "Conv2D", [[1, 3, 12, 12]]))
+        self.unit_test_export(model, "Conv2D", [[1, 3, 12, 12]], False, False)
 
     def test_export_max_pooling(self):
         print("MaxPooling2D")
@@ -269,7 +234,7 @@ class test_operator_export(unittest.TestCase):
             aidge_core.MaxPooling2D(kernel_dims=(3, 3), name="max_pool")
         ])
 
-        self.assertTrue(unit_test_export(model, "MaxPooling2D", [[1, 2, 12, 12]]))
+        self.unit_test_export(model, "MaxPooling2D", [[1, 2, 12, 12]], False, False)
 
     def test_export_avg_pooling(self):
         print("AvgPooling2D")
@@ -277,7 +242,7 @@ class test_operator_export(unittest.TestCase):
             aidge_core.AvgPooling2D(kernel_dims=(3, 3), name="avg_pool")
         ])
 
-        self.assertTrue(unit_test_export(model, "AvgPooling2D", [[1, 2, 12, 12]]))
+        self.unit_test_export(model, "AvgPooling2D", [[1, 2, 12, 12]], False, False)
 
     def test_export_pad2D(self):
         print("Pad2D")
@@ -285,7 +250,7 @@ class test_operator_export(unittest.TestCase):
             aidge_core.Pad2D((1, 1, 1, 1), name="pad2d")
         ])
 
-        self.assertTrue(unit_test_export(model, "Pad2D", [[1, 3, 10, 10]]))
+        self.unit_test_export(model, "Pad2D", [[1, 1, 10, 10]])
 
     def test_export_batchnorm2D(self):
         print("BatchNormalization2D")
@@ -293,7 +258,8 @@ class test_operator_export(unittest.TestCase):
             aidge_core.BatchNorm2D(nb_features=10, epsilon=2e-5, name="bn")
         ])
 
-        self.assertTrue(unit_test_export(model, "BatchNorm2D", [[1, 10, 5, 5]]))
+        self.unit_test_export(model, "BatchNorm2D", [[1, 1, 5, 5]], False, False)
+
 
     def test_export_cpp(self):
         print("Export test to do")