diff --git a/include/aidge/data/Tensor.hpp b/include/aidge/data/Tensor.hpp
index 3ee64cecaf9b139ec0a7ef9a0fa4acc5b06f57c7..89d7a3a7b0c4d164473869a9d6372c3bf48cd308 100644
--- a/include/aidge/data/Tensor.hpp
+++ b/include/aidge/data/Tensor.hpp
@@ -449,12 +449,16 @@ public:
      */
     constexpr inline const std::vector<DimSize_t>& dims() const noexcept { return mDims; }
 
+    inline DimSize_t dim(DimIdx_t idx) const { return mDims[idx]; }
+
     /**
      * @brief Get strides of the Tensor object.
      * @return constexpr const std::vector<DimSize_t>&
      */
     constexpr inline const std::vector<DimSize_t>& strides() const noexcept { return mStrides; }
 
+    inline DimSize_t stride(DimIdx_t idx) const { return mStrides[idx]; }
+
     /**
      * @brief Return true if Tensor is contiguous in memory.
      * @return bool
diff --git a/include/aidge/operator/GridSample.hpp b/include/aidge/operator/GridSample.hpp
index af44a5df5de6908d58951b93921d49ec8e7df708..81900824ed0d26572e593982fa21ed900eda88ee 100644
--- a/include/aidge/operator/GridSample.hpp
+++ b/include/aidge/operator/GridSample.hpp
@@ -27,15 +27,14 @@ namespace Aidge {
 
 enum class GridSampleAttr { Mode, PaddingMode, AlignCorners };
 
-template <DimIdx_t DIM>
 class GridSample_Op : public OperatorTensor,
-	public Registrable<GridSample_Op<DIM>, std::string, std::shared_ptr<OperatorImpl>(const GridSample_Op<DIM>&)> {
+	public Registrable<GridSample_Op, std::string, std::shared_ptr<OperatorImpl>(const GridSample_Op&)> {
 
 public:
 	static const std::string Type;
 
 	enum class Mode { Linear, Nearest, Cubic };
-	enum class PaddingMode { Zeros, Border, Reflexion };
+	enum class PaddingMode { Zeros, Border, Reflection };
 
 private:
 	using Attributes_ = StaticAttributes<GridSampleAttr, Mode, PaddingMode, bool>;
@@ -49,7 +48,7 @@ public:
 			PaddingMode paddingMode = PaddingMode::Zeros,
 			bool alignCorners = false);
 
-	GridSample_Op(const GridSample_Op<DIM>& other);
+	GridSample_Op(const GridSample_Op& other);
 	~GridSample_Op() noexcept;
 
 public:
@@ -63,7 +62,7 @@ public:
 	inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; }
 	inline Mode mode() const { return mAttributes->template getAttr<GridSampleAttr::Mode>(); }
 	inline PaddingMode paddingMode() const { return mAttributes->template getAttr<GridSampleAttr::PaddingMode>(); }
-	inline bool alignBorders() const { return mAttributes->template getAttr<GridSampleAttr::AlignCorners>(); }
+	inline bool alignCorners() const { return mAttributes->template getAttr<GridSampleAttr::AlignCorners>(); }
 
 	static const std::vector<std::string> getInputsName() {
 		return {"data_input", "grid_field"};
@@ -73,13 +72,9 @@ public:
 	}
 };
 
-extern template class GridSample_Op<1>;
-extern template class GridSample_Op<2>;
-
-template <DimIdx_t DIM>
 std::shared_ptr<Node> GridSample(
-                        typename GridSample_Op<DIM>::Mode mode = GridSample_Op<DIM>::Mode::Linear,
-                        typename GridSample_Op<DIM>::PaddingMode paddingMode = GridSample_Op<DIM>::PaddingMode::Zeros,
+                        typename GridSample_Op::Mode mode = GridSample_Op::Mode::Linear,
+                        typename GridSample_Op::PaddingMode paddingMode = GridSample_Op::PaddingMode::Zeros,
                         bool alignCorners = false,
                         const std::string& name = "");
 
diff --git a/python_binding/operator/pybind_GridSample.cpp b/python_binding/operator/pybind_GridSample.cpp
index 34d1ff295093dd35fe5e71cdf335e6147d08194e..49e74f4cbab90f141af5e76df7fbdef6e3794146 100644
--- a/python_binding/operator/pybind_GridSample.cpp
+++ b/python_binding/operator/pybind_GridSample.cpp
@@ -22,58 +22,51 @@
 #include "aidge/utils/Types.h"
 #include "aidge/utils/Registrar.hpp" // declare_registrable
 
-template <std::size_t DIM>
-static typename Aidge::GridSample_Op<DIM>::Mode stringToInterpolationMode(const std::string& mode) {
-    static std::unordered_map<std::string, typename Aidge::GridSample_Op<DIM>::Mode> map = {
-        {"linear", Aidge::GridSample_Op<DIM>::Mode::Linear},
-        {"nearest", Aidge::GridSample_Op<DIM>::Mode::Nearest},
-        {"cubic", Aidge::GridSample_Op<DIM>::Mode::Cubic}
+
+static typename Aidge::GridSample_Op::Mode stringToInterpolationMode(const std::string& mode) {
+    static std::unordered_map<std::string, typename Aidge::GridSample_Op::Mode> map = {
+        {"linear", Aidge::GridSample_Op::Mode::Linear},
+        {"nearest", Aidge::GridSample_Op::Mode::Nearest},
+        {"cubic", Aidge::GridSample_Op::Mode::Cubic}
     };
     return map[mode];
 }
 
-template Aidge::GridSample_Op<1>::Mode stringToInterpolationMode<1>(const std::string&);
-template Aidge::GridSample_Op<2>::Mode stringToInterpolationMode<2>(const std::string&);
-
-template <std::size_t DIM>
-static typename Aidge::GridSample_Op<DIM>::PaddingMode stringToPaddingMode(const std::string& mode) {
-    static std::unordered_map<std::string, typename Aidge::GridSample_Op<DIM>::PaddingMode> map = {
-        {"zeros", Aidge::GridSample_Op<DIM>::PaddingMode::Zeros},
-        {"border", Aidge::GridSample_Op<DIM>::PaddingMode::Border},
-        {"reflexion", Aidge::GridSample_Op<DIM>::PaddingMode::Reflexion}
+static typename Aidge::GridSample_Op::PaddingMode stringToPaddingMode(const std::string& mode) {
+    static std::unordered_map<std::string, typename Aidge::GridSample_Op::PaddingMode> map = {
+        {"zeros", Aidge::GridSample_Op::PaddingMode::Zeros},
+        {"border", Aidge::GridSample_Op::PaddingMode::Border},
+        {"reflection", Aidge::GridSample_Op::PaddingMode::Reflection}
     };
     return map[mode];
 }
 
-template Aidge::GridSample_Op<1>::PaddingMode stringToPaddingMode<1>(const std::string&);
-template Aidge::GridSample_Op<2>::PaddingMode stringToPaddingMode<2>(const std::string&);
-
 namespace py = pybind11;
 namespace Aidge {
 
-template <DimIdx_t DIM> void declare_GridSampleOp(py::module &m) {
-  const std::string pyClassName("GridSampleOp" + std::to_string(DIM) + "D");
-  py::class_<GridSample_Op<DIM>, std::shared_ptr<GridSample_Op<DIM>>, OperatorTensor>(
+void declare_GridSampleOp(py::module &m) {
+  const std::string pyClassName("GridSampleOp");
+  py::class_<GridSample_Op, std::shared_ptr<GridSample_Op>, OperatorTensor>(
     m, pyClassName.c_str(),
     py::multiple_inheritance())
         .def(py::init([](const std::string& mode,
                          const std::string& padding_mode,
                          bool align_corners) {
-            return new GridSample_Op<DIM>(stringToInterpolationMode<DIM>(mode), stringToPaddingMode<DIM>(padding_mode), align_corners);
+            return new GridSample_Op(stringToInterpolationMode(mode), stringToPaddingMode(padding_mode), align_corners);
         }), py::arg("mode") = "linear",
             py::arg("padding_mode") = "zeros",
             py::arg("alogn_corners") = false)
-        .def_static("get_inputs_name", &GridSample_Op<DIM>::getInputsName)
-        .def_static("get_outputs_name", &GridSample_Op<DIM>::getOutputsName)
+        .def_static("get_inputs_name", &GridSample_Op::getInputsName)
+        .def_static("get_outputs_name", &GridSample_Op::getOutputsName)
         ;
 
-  declare_registrable<GridSample_Op<DIM>>(m, pyClassName);
+  declare_registrable<GridSample_Op>(m, pyClassName);
 
-  m.def(("GridSample" + std::to_string(DIM) + "D").c_str(), [](const std::string& mode,
-                                                        const std::string& padding_mode,
-                                                        bool align_corners,
-                                                        const std::string& name) {
-        return GridSample<DIM>(stringToInterpolationMode<DIM>(mode), stringToPaddingMode<DIM>(padding_mode), align_corners, name);
+  m.def("GridSample", [](const std::string& mode,
+                        const std::string& padding_mode,
+                        bool align_corners,
+                        const std::string& name) {
+        return GridSample(stringToInterpolationMode(mode), stringToPaddingMode(padding_mode), align_corners, name);
     }, py::arg("mode"),
        py::arg("padding_mode"),
        py::arg("align_corners"),
@@ -82,9 +75,7 @@ template <DimIdx_t DIM> void declare_GridSampleOp(py::module &m) {
 
 
 void init_GridSample(py::module &m) {
-  declare_GridSampleOp<1>(m);
-  declare_GridSampleOp<2>(m);
-//   declare_GridSampleOp<3>(m);
+  declare_GridSampleOp(m);
 }
 
 } // namespace Aidge
diff --git a/src/operator/Fold.cpp b/src/operator/Fold.cpp
index 997348d406db6ed4393362941099c93b03d5b9e8..1a2ec88bbfb2bfed134e779619a0a3f0604ce155 100644
--- a/src/operator/Fold.cpp
+++ b/src/operator/Fold.cpp
@@ -97,4 +97,4 @@ std::shared_ptr<Aidge::Node> Aidge::Fold(const std::array<Aidge::DimSize_t, DIM>
     return std::make_shared<Node>(std::make_shared<Fold_Op<static_cast<DimIdx_t>(DIM)>>(outputDims, kernelDims, strideDims, dilationDims), name);
 }
 
-template std::shared_ptr<Aidge::Node> Aidge::Fold<2>(const std::array<Aidge::DimSize_t, 2> &outputDims, const std::array<Aidge::DimSize_t, 2> &kernelDims, const std::string& name, const std::array<Aidge::DimSize_t, 2> &strideDims, const std::array<Aidge::DimSize_t, 2> &dilationDims);
+template std::shared_ptr<Aidge::Node> Aidge::Fold<2>(const std::array<Aidge::DimSize_t, 2>&, const std::array<Aidge::DimSize_t, 2>&, const std::string&, const std::array<Aidge::DimSize_t, 2>&, const std::array<Aidge::DimSize_t, 2>&);
\ No newline at end of file
diff --git a/src/operator/GridSample.cpp b/src/operator/GridSample.cpp
index 6cc0ad7462886e5491ba697dbbe868a5f47e4dd4..fa1efc75a4c0a85717343ce4fcdea1a8adcfb4e7 100644
--- a/src/operator/GridSample.cpp
+++ b/src/operator/GridSample.cpp
@@ -21,13 +21,13 @@
 #include "aidge/utils/Registrar.hpp"
 #include "aidge/utils/Types.h"
 
-template <Aidge::DimIdx_t DIM>
-const std::string Aidge::GridSample_Op<DIM>::Type = "GridSample";
 
-template <Aidge::DimIdx_t DIM>
-Aidge::GridSample_Op<DIM>::GridSample_Op(
-    typename Aidge::GridSample_Op<DIM>::Mode mode,
-    typename Aidge::GridSample_Op<DIM>::PaddingMode paddingMode,
+const std::string Aidge::GridSample_Op::Type = "GridSample";
+
+
+Aidge::GridSample_Op::GridSample_Op(
+    typename Aidge::GridSample_Op::Mode mode,
+    typename Aidge::GridSample_Op::PaddingMode paddingMode,
     bool alignCorners)
     : OperatorTensor(Type, {InputCategory::Data, InputCategory::Param}, 1),
       mAttributes(std::make_shared<Attributes_>(
@@ -38,46 +38,47 @@ Aidge::GridSample_Op<DIM>::GridSample_Op(
     // ctor
 }
 
-template <Aidge::DimIdx_t DIM>
-Aidge::GridSample_Op<DIM>::GridSample_Op(const Aidge::GridSample_Op<DIM>& other)
+
+Aidge::GridSample_Op::GridSample_Op(const Aidge::GridSample_Op& other)
     : OperatorTensor(other),
       mAttributes(other.mAttributes)
 {
     if (other.mImpl) {
-        SET_IMPL_MACRO(GridSample_Op<DIM>, *this, other.backend());
+        SET_IMPL_MACRO(GridSample_Op, *this, other.backend());
     } else {
         mImpl = nullptr;
     }
 }
 
-template <Aidge::DimIdx_t DIM>
-Aidge::GridSample_Op<DIM>::~GridSample_Op() noexcept = default;
 
-template <Aidge::DimIdx_t DIM>
-std::shared_ptr<Aidge::Operator> Aidge::GridSample_Op<DIM>::clone() const {
-    return std::make_shared<GridSample_Op<DIM>>(*this);
+Aidge::GridSample_Op::~GridSample_Op() noexcept = default;
+
+
+std::shared_ptr<Aidge::Operator> Aidge::GridSample_Op::clone() const {
+    return std::make_shared<GridSample_Op>(*this);
 }
 
-template <Aidge::DimIdx_t DIM>
-bool Aidge::GridSample_Op<DIM>::forwardDims(bool /*allowDataDependency*/) {
+
+bool Aidge::GridSample_Op::forwardDims(bool /*allowDataDependency*/) {
     // TODO: adapt for other formats than NCHW
     if (inputsAssociated()) {
         // check data has batch and channel dimensions: (N, C, D0, D1, ..., DN)
-        AIDGE_ASSERT((getInput(0)->nbDims() == (DIM+2)),
-                    "Wrong input size for {} operator.", type());
+        AIDGE_ASSERT(getInput(0)->nbDims() > 2, "Input should have at least one spatial dimension.");
+        const std::size_t nbSpatialFeat = getInput(0)->nbDims() -2; // all except channels and batchs
         // check grid field
         // should be (N, D0_out, D1_out, ..., DN_out, N+1)
-        AIDGE_ASSERT(((getInput(1)->nbDims() == (DIM+2)) &&
-            (getInput(1)->template dims<DIM+2>()[DIM+1] == DIM) &&
-            (getInput(1)->template dims<DIM+2>()[0] == getInput(0)->template dims<DIM+2>()[0])),
+        AIDGE_ASSERT(((getInput(1)->nbDims() == nbSpatialFeat + 2) &&
+            (getInput(1)->dims()[nbSpatialFeat+1] == nbSpatialFeat) &&
+            (getInput(1)->dims()[0] == getInput(0)->dims()[0])),
             "Wrong grid size {} for {} operator.", getInput(1)->dims(), type());
 
-        std::array<DimSize_t, DIM + 2> outputDims{};
+        std::vector<DimSize_t> outputDims{};
+        outputDims.reserve(nbSpatialFeat+2);
         const std::vector<DimSize_t>& inputDims(getInput(1)->dims());
-        outputDims[1] = getInput(0)->template dims<DIM+2>()[1];
-        outputDims[0] = inputDims[0];
-        for (std::size_t i = 2; i < DIM+2; ++i) {
-            outputDims[i] = inputDims[i-1];
+        outputDims.push_back(inputDims[0]);
+        outputDims.push_back(getInput(0)->dims()[1]);
+        for (std::size_t i = 2; i < nbSpatialFeat+2; ++i) {
+            outputDims.push_back(inputDims[i-1]);
         }
 
         mOutputs[0]->resize(outputDims);
@@ -88,31 +89,26 @@ bool Aidge::GridSample_Op<DIM>::forwardDims(bool /*allowDataDependency*/) {
 }
 
 
-template <Aidge::DimIdx_t DIM>
-void Aidge::GridSample_Op<DIM>::setBackend(const std::string &name, Aidge::DeviceIdx_t device) {
-    SET_IMPL_MACRO(GridSample_Op<DIM>, *this, name);
+
+void Aidge::GridSample_Op::setBackend(const std::string &name, Aidge::DeviceIdx_t device) {
+    SET_IMPL_MACRO(GridSample_Op, *this, name);
     mOutputs[0]->setBackend(name, device);
 }
 
-template class Aidge::GridSample_Op<1>;
-template class Aidge::GridSample_Op<2>;
 
 ////////////////////////////////////////////////
 
-template <Aidge::DimIdx_t DIM>
+
 std::shared_ptr<Aidge::Node> Aidge::GridSample(
-                        typename Aidge::GridSample_Op<DIM>::Mode mode,
-                        typename Aidge::GridSample_Op<DIM>::PaddingMode paddingMode,
+                        typename Aidge::GridSample_Op::Mode mode,
+                        typename Aidge::GridSample_Op::PaddingMode paddingMode,
                         bool alignCorners,
                         const std::string& name)
 {
     return std::make_shared<Node>(
-        std::make_shared<GridSample_Op<DIM>>(
+        std::make_shared<GridSample_Op>(
                 mode,
                 paddingMode,
                 alignCorners),
             name);
 }
-
-template std::shared_ptr<Aidge::Node> Aidge::GridSample<1>(typename Aidge::GridSample_Op<1>::Mode, typename Aidge::GridSample_Op<1>::PaddingMode, bool, const std::string&);
-template std::shared_ptr<Aidge::Node> Aidge::GridSample<2>(typename Aidge::GridSample_Op<2>::Mode, typename Aidge::GridSample_Op<2>::PaddingMode, bool, const std::string&);
diff --git a/unit_tests/operator/Test_GridSample_Op.cpp b/unit_tests/operator/Test_GridSample_Op.cpp
index 754cdb705dcbc5115af32bb0994fbb08ba633c3f..ae38ec7083a0df49fb241509bf52895765ddb0e8 100644
--- a/unit_tests/operator/Test_GridSample_Op.cpp
+++ b/unit_tests/operator/Test_GridSample_Op.cpp
@@ -33,7 +33,7 @@ TEST_CASE("[core/operator] GridSample_Op(forwardDims)", "[GridSample][forwardDim
     std::uniform_int_distribution<std::size_t> nbDimsDist(1, 5);
 
     // Create GridSample Operator
-    std::shared_ptr<Node> myGridSample = GridSample<2>(GridSample_Op<2>::Mode::Cubic, GridSample_Op<2>::PaddingMode::Border, false);
+    std::shared_ptr<Node> myGridSample = GridSample(GridSample_Op::Mode::Cubic, GridSample_Op::PaddingMode::Border, false);
     auto op = std::static_pointer_cast<OperatorTensor>(myGridSample -> getOperator());
 
     // input_0