diff --git a/python_binding/operator/pybind_Expand.cpp b/python_binding/operator/pybind_Expand.cpp
index ce8a32329ab51ea3086c689b0156b62244f752c2..c20e47e849bbfad7331b8f5f2de82bc32bda033e 100644
--- a/python_binding/operator/pybind_Expand.cpp
+++ b/python_binding/operator/pybind_Expand.cpp
@@ -50,11 +50,11 @@ void init_Expand(py::module &m) {
 
     declare_registrable<Expand_Op>(m, pyClassName);
 
-    m.def("expand",
+    m.def("Expand",
           &Expand,
           py::arg("name") = "",
           R"mydelimiter(
-    Initialize a node containing an expand operator.
+    Initialize a node containing an Expand operator.
     This operator will broadcast values given via input#0 to a shape given via input#1's values
     If one of the inputs has less dimensions than the other, dimension will be appended 1's to the left.
 
diff --git a/python_binding/operator/pybind_Fold.cpp b/python_binding/operator/pybind_Fold.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..747abc1611a1a51d9b317de365b5036436b1494a
--- /dev/null
+++ b/python_binding/operator/pybind_Fold.cpp
@@ -0,0 +1,107 @@
+#include <pybind11/pybind11.h>
+#include <pybind11/stl.h>
+#include <string>
+#include <vector>
+#include <array>
+
+#include "aidge/backend/OperatorImpl.hpp"
+#include "aidge/data/Tensor.hpp"
+#include "aidge/operator/Fold.hpp"
+#include "aidge/operator/OperatorTensor.hpp"
+#include "aidge/utils/Types.h"
+#include "aidge/utils/Registrar.hpp" // declare_registrable
+
+namespace py = pybind11;
+namespace Aidge {
+
+template <DimIdx_t DIM> 
+void declare_FoldOp(py::module &m) {
+  const std::string pyClassName("Fold" + std::to_string(DIM) + "DOp");
+  py::class_<Fold_Op<DIM>, std::shared_ptr<Fold_Op<DIM>>, OperatorTensor>(
+    m, pyClassName.c_str(),
+    py::multiple_inheritance(),
+    R"mydelimiter(
+    Initialize a Fold operator.
+
+    :param output_dims : The dimensions of output.
+    :type output_dims : List[int]
+    :param kernel_dims : The dimensions of the fold kernel (filter size).
+    :type kernel_dims : List[int]
+    :param stride_dims : The stride size for the fold.
+    :type stride_dims : List[int]
+    :param dilation_dims : The dilation size for the fold.
+    :type dilation_dims : List[int]
+    )mydelimiter")
+        .def(py::init([](const std::vector<DimSize_t>& output_dims,
+                         const std::vector<DimSize_t>& kernel_dims,
+                         const std::vector<DimSize_t> &stride_dims,
+                         const std::vector<DimSize_t> &dilation_dims) {
+            AIDGE_ASSERT(output_dims.size() == DIM, "output_dims size [{}] does not match DIM [{}]", output_dims.size(), DIM);
+            AIDGE_ASSERT(kernel_dims.size() == DIM, "kernel_dims size [{}] does not match DIM [{}]", kernel_dims.size(), DIM);
+            AIDGE_ASSERT(stride_dims.size() == DIM, "stride_dims size [{}] does not match DIM [{}]", stride_dims.size(), DIM);
+            AIDGE_ASSERT(dilation_dims.size() == DIM, "dilation_dims size [{}] does not match DIM [{}]", dilation_dims.size(), DIM);
+
+            return new Fold_Op<DIM>(to_array<DIM>(output_dims.begin()), to_array<DIM>(kernel_dims.begin()), to_array<DIM>(stride_dims.begin()), to_array<DIM>(dilation_dims.begin()));
+        }), py::arg("output_dims"),
+            py::arg("kernel_dims"),
+            py::arg("stride_dims") = std::vector<DimSize_t>(DIM,1),
+            py::arg("dilation_dims") = std::vector<DimSize_t>(DIM,1))
+        .def_static("get_inputs_name", &Fold_Op<DIM>::getInputsName)
+        .def_static("get_outputs_name", &Fold_Op<DIM>::getOutputsName)
+
+		.def_static("attributes_name", []() {
+			std::vector<std::string> result;
+			auto attributes = Fold_Op<DIM>::attributesName();
+			for (size_t i = 0; i < size(EnumStrings<FoldAttr>::data); ++i) {
+				result.emplace_back(attributes[i]);
+			}
+			return result;
+		})
+        .def_readonly_static("Type", &Fold_Op<DIM>::Type)
+        ;
+
+  declare_registrable<Fold_Op<DIM>>(m, pyClassName);
+
+  m.def(("Fold" + std::to_string(DIM) + "D").c_str(), [](const std::vector<DimSize_t>& output_dims,
+                                                         const std::vector<DimSize_t>& kernel_dims,
+                                                         const std::string& name,
+                                                         const std::vector<DimSize_t> &stride_dims,
+                                                         const std::vector<DimSize_t> &dilation_dims) {
+        AIDGE_ASSERT(output_dims.size() == DIM, "output_dims size [{}] does not match DIM [{}]", output_dims.size(), DIM);
+        AIDGE_ASSERT(kernel_dims.size() == DIM, "kernel_dims size [{}] does not match DIM [{}]", kernel_dims.size(), DIM);
+        AIDGE_ASSERT(stride_dims.size() == DIM, "stride_dims size [{}] does not match DIM [{}]", stride_dims.size(), DIM);
+        AIDGE_ASSERT(dilation_dims.size() == DIM, "dilation_dims size [{}] does not match DIM [{}]", dilation_dims.size(), DIM);
+
+        return Fold<DIM>(to_array<DIM>(output_dims.begin()), to_array<DIM>(kernel_dims.begin()), name, to_array<DIM>(stride_dims.begin()), to_array<DIM>(dilation_dims.begin()));
+    }, 
+    py::arg("output_dims"),
+    py::arg("kernel_dims"),
+    py::arg("name") = "",
+    py::arg("stride_dims") = std::vector<DimSize_t>(DIM,1),
+    py::arg("dilation_dims") = std::vector<DimSize_t>(DIM,1),
+    R"mydelimiter(
+    Initialize a node containing a Fold operator.
+
+    :param output_dims : The dimensions of output.
+    :type output_dims : List[int]
+    :param kernel_dims : The dimensions of the fold kernel (filter size).
+    :type kernel_dims : List[int]
+    :param name : The name of the operator (optional).
+    :type name : str
+    :param stride_dims : The stride size for the fold (default is [1]).
+    :type stride_dims : List[int]
+    :param dilation_dims : The dilation size for the fold (default is [1]).
+    :type dilation_dims : List[int]
+    :return : A new Fold operator node.
+    :rtype : :py:class:`FoldOp`
+    )mydelimiter");
+}
+
+
+void init_Fold(py::module &m) {
+//  declare_FoldOp<1>(m);
+  declare_FoldOp<2>(m);
+//   declare_FoldOp<3>(m);
+}
+
+} // namespace Aidge
diff --git a/python_binding/operator/pybind_Unfold.cpp b/python_binding/operator/pybind_Unfold.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..86f8f26d63ef1c59ad68842a6e7291fa4706e8e1
--- /dev/null
+++ b/python_binding/operator/pybind_Unfold.cpp
@@ -0,0 +1,97 @@
+#include <pybind11/pybind11.h>
+#include <pybind11/stl.h>
+#include <string>
+#include <vector>
+#include <array>
+
+#include "aidge/backend/OperatorImpl.hpp"
+#include "aidge/data/Tensor.hpp"
+#include "aidge/operator/Unfold.hpp"
+#include "aidge/operator/OperatorTensor.hpp"
+#include "aidge/utils/Types.h"
+#include "aidge/utils/Registrar.hpp" // declare_registrable
+
+namespace py = pybind11;
+namespace Aidge {
+
+template <DimIdx_t DIM> 
+void declare_UnfoldOp(py::module &m) {
+  const std::string pyClassName("Unfold" + std::to_string(DIM) + "DOp");
+  py::class_<Unfold_Op<DIM>, std::shared_ptr<Unfold_Op<DIM>>, OperatorTensor>(
+    m, pyClassName.c_str(),
+    py::multiple_inheritance(),
+    R"mydelimiter(
+    Initialize a Unfold operator.
+
+    :param kernel_dims : The dimensions of the unfold kernel (filter size).
+    :type kernel_dims : List[int]
+    :param stride_dims : The stride size for the unfold.
+    :type stride_dims : List[int]
+    :param dilation_dims : The dilation size for the unfold.
+    :type dilation_dims : List[int]
+    )mydelimiter")
+        .def(py::init([](const std::vector<DimSize_t>& kernel_dims,
+                         const std::vector<DimSize_t> &stride_dims,
+                         const std::vector<DimSize_t> &dilation_dims) {
+            AIDGE_ASSERT(kernel_dims.size() == DIM, "kernel_dims size [{}] does not match DIM [{}]", kernel_dims.size(), DIM);
+            AIDGE_ASSERT(stride_dims.size() == DIM, "stride_dims size [{}] does not match DIM [{}]", stride_dims.size(), DIM);
+            AIDGE_ASSERT(dilation_dims.size() == DIM, "dilation_dims size [{}] does not match DIM [{}]", dilation_dims.size(), DIM);
+
+            return new Unfold_Op<DIM>(to_array<DIM>(kernel_dims.begin()), to_array<DIM>(stride_dims.begin()), to_array<DIM>(dilation_dims.begin()));
+        }), py::arg("kernel_dims"),
+            py::arg("stride_dims") = std::vector<DimSize_t>(DIM,1),
+            py::arg("dilation_dims") = std::vector<DimSize_t>(DIM,1))
+        .def_static("get_inputs_name", &Unfold_Op<DIM>::getInputsName)
+        .def_static("get_outputs_name", &Unfold_Op<DIM>::getOutputsName)
+
+		.def_static("attributes_name", []() {
+			std::vector<std::string> result;
+			auto attributes = Unfold_Op<DIM>::attributesName();
+			for (size_t i = 0; i < size(EnumStrings<UnfoldAttr>::data); ++i) {
+				result.emplace_back(attributes[i]);
+			}
+			return result;
+		})
+        .def_readonly_static("Type", &Unfold_Op<DIM>::Type)
+        ;
+
+  declare_registrable<Unfold_Op<DIM>>(m, pyClassName);
+
+  m.def(("Unfold" + std::to_string(DIM) + "D").c_str(), [](const std::vector<DimSize_t>& kernel_dims,
+                                                         const std::string& name,
+                                                         const std::vector<DimSize_t> &stride_dims,
+                                                         const std::vector<DimSize_t> &dilation_dims) {
+        AIDGE_ASSERT(kernel_dims.size() == DIM, "kernel_dims size [{}] does not match DIM [{}]", kernel_dims.size(), DIM);
+        AIDGE_ASSERT(stride_dims.size() == DIM, "stride_dims size [{}] does not match DIM [{}]", stride_dims.size(), DIM);
+        AIDGE_ASSERT(dilation_dims.size() == DIM, "dilation_dims size [{}] does not match DIM [{}]", dilation_dims.size(), DIM);
+
+        return Unfold<DIM>(to_array<DIM>(kernel_dims.begin()), name, to_array<DIM>(stride_dims.begin()), to_array<DIM>(dilation_dims.begin()));
+    }, 
+    py::arg("kernel_dims"),
+    py::arg("name") = "",
+    py::arg("stride_dims") = std::vector<DimSize_t>(DIM,1),
+    py::arg("dilation_dims") = std::vector<DimSize_t>(DIM,1),
+    R"mydelimiter(
+    Initialize a node containing a Unfold operator.
+
+    :param kernel_dims : The dimensions of the unfold kernel (filter size).
+    :type kernel_dims : List[int]
+    :param name : The name of the operator (optional).
+    :type name : str
+    :param stride_dims : The stride size for the unfold (default is [1]).
+    :type stride_dims : List[int]
+    :param dilation_dims : The dilation size for the unfold (default is [1]).
+    :type dilation_dims : List[int]
+    :return : A new Unfold operator node.
+    :rtype : :py:class:`UnfoldOp`
+    )mydelimiter");
+}
+
+
+void init_Unfold(py::module &m) {
+//  declare_UnfoldOp<1>(m);
+  declare_UnfoldOp<2>(m);
+//   declare_UnfoldOp<3>(m);
+}
+
+} // namespace Aidge
diff --git a/python_binding/pybind_core.cpp b/python_binding/pybind_core.cpp
index 7fef82847f3a9e5252e14c1aff584b21f182e36c..de045a4c928299200089adf060d0195ee7b59c60 100644
--- a/python_binding/pybind_core.cpp
+++ b/python_binding/pybind_core.cpp
@@ -61,6 +61,7 @@ void init_Erf(py::module&);
 void init_Expand(py::module&);
 void init_FC(py::module&);
 void init_Flatten(py::module&);
+void init_Fold(py::module&);
 void init_Gather(py::module&);
 void init_GenericOperator(py::module&);
 void init_GlobalAveragePooling(py::module&);
@@ -98,6 +99,7 @@ void init_Stack(py::module&);
 void init_Sub(py::module&);
 void init_Tanh(py::module&);
 void init_Transpose(py::module&);
+void init_Unfold(py::module&);
 void init_Unsqueeze(py::module&);
 void init_WeightInterleaving(py::module&);
 
@@ -169,6 +171,7 @@ void init_Aidge(py::module& m) {
     init_Expand(m);
     init_FC(m);
     init_Flatten(m);
+    init_Fold(m);
     init_Gather(m);
     init_GenericOperator(m);
     init_GlobalAveragePooling(m);
@@ -205,6 +208,7 @@ void init_Aidge(py::module& m) {
     init_Sub(m);
     init_Tanh(m);
     init_Transpose(m);
+    init_Unfold(m);
     init_Unsqueeze(m);
     init_WeightInterleaving(m);
 
diff --git a/src/graph/Node.cpp b/src/graph/Node.cpp
index 33c336a843bcf168497cd86fea241d4ad2dec362..8a3975ece23e7951f51be455a13a0460813f1b73 100644
--- a/src/graph/Node.cpp
+++ b/src/graph/Node.cpp
@@ -349,11 +349,11 @@ void Aidge::Node::addChildOp(const std::shared_ptr<Node>& otherNode, const IOInd
     AIDGE_ASSERT(outId < nbOutputs(),
         "Output index (#{}) of the node {} (of type {}) is out of bound (it has {} outputs), when trying to add the child node {} (of type {})",
         outId, name(), type(), nbOutputs(), otherNode->name(), otherNode->type());
-    if (otherNode.use_count() == 1) {
-        Log::debug("Node::addChild(): the node {} (of type {}) only holds a weak reference to the added child node {} (of type {})."
-            "If the child node goes out of scope, it will be destructed, leading to a dangling connection."
-            "To avoid this message, consider adding the child node to a GraphView first.", name(), type(), otherNode->name(), otherNode->type());
-    }
+    // if (otherNode.use_count() == 1) {
+    //     Log::debug("Node::addChild(): the node {} (of type {}) only holds a weak reference to the added child node {} (of type {})."
+    //         "If the child node goes out of scope, it will be destructed, leading to a dangling connection."
+    //         "To avoid this message, consider adding the child node to a GraphView first.", name(), type(), otherNode->name(), otherNode->type());
+    // }
     if (otherNode->input(otherInId).second != gk_IODefaultIndex) {
         Log::notice("the {}-th Parent of the child node {} (of type {}) already existed", otherInId, otherNode->name(), otherNode->type());
     }