diff --git a/aidge_backend_cpu/unit_tests/test_tensor.py b/aidge_backend_cpu/unit_tests/test_tensor.py
deleted file mode 100644
index 37531b43cf7755dfb760e575450b70bfa9a6ff68..0000000000000000000000000000000000000000
--- a/aidge_backend_cpu/unit_tests/test_tensor.py
+++ /dev/null
@@ -1,71 +0,0 @@
-import unittest
-import aidge_core
-import aidge_backend_cpu
-import numpy as np
-
-
-class test_tensor(unittest.TestCase):
-    """Test tensor binding
-    """
-    def setUp(self):
-        pass
-    def tearDown(self):
-        pass
-
-    def test_getavailable_backends(self):
-        self.assertTrue("cpu" in aidge_core.Tensor.get_available_backends())
-
-    def test_numpy_int_to_tensor(self):
-        np_array = np.arange(9).reshape(1,1,3,3).astype(np.int32)
-        # Numpy -> Tensor
-        t = aidge_core.Tensor(np_array)
-        self.assertEqual(t.dtype(), aidge_core.DataType.Int32)
-        for i_t, i_n in zip(t, np_array.flatten()):
-            self.assertTrue(i_t == i_n)
-        for i,j in zip(t.dims(), np_array.shape):
-            self.assertEqual(i,j)
-    def test_tensor_int_to_numpy(self):
-        np_array = np.arange(9).reshape(1,1,3,3)
-        # Numpy -> Tensor
-        t = aidge_core.Tensor(np_array)
-        # Tensor -> Numpy
-        nnarray = np.array(t)
-        for i_nn, i_n in zip(nnarray.flatten(), np_array.flatten()):
-            self.assertTrue(i_nn == i_n)
-        for i,j in zip(t.dims(), nnarray.shape):
-            self.assertEqual(i,j)
-
-    def test_numpy_int64_to_tensor(self):
-        np_array = np.arange(9).reshape(1,1,3,3).astype(np.int64)
-        # Numpy -> Tensor
-        t = aidge_core.Tensor(np_array)
-        self.assertEqual(t.dtype(), aidge_core.DataType.Int64)
-        for i_t, i_n in zip(t, np_array.flatten()):
-            self.assertTrue(i_t == i_n)
-        for i,j in zip(t.dims(), np_array.shape):
-            self.assertEqual(i,j)
-
-    def test_numpy_float_to_tensor(self):
-        t = aidge_core.Tensor()
-        np_array = np.random.rand(1, 1, 3, 3).astype(np.float32)
-        # Numpy -> Tensor
-        t = aidge_core.Tensor(np_array)
-        self.assertEqual(t.dtype(), aidge_core.DataType.Float32)
-        for i_t, i_n in zip(t, np_array.flatten()):
-            self.assertTrue(i_t == i_n) # TODO : May need to change this to a difference
-        for i,j in zip(t.dims(), np_array.shape):
-            self.assertEqual(i,j)
-
-    def test_get_set(self):
-        dims = [2,2,2]
-
-        np_array = np.arange(8).reshape(dims).astype(np.int32)
-        # Numpy -> Tensor
-        t = aidge_core.Tensor(np_array)
-        for i in range(8):
-            self.assertEqual(t[i], i)
-            t[i] = 5
-            self.assertEqual(t[i], 5)
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/include/aidge/backend/cpu.hpp b/include/aidge/backend/cpu.hpp
index 2020c9dbcd1b0ed690e499bca44bbb70c49f7e45..8fae3439c9e5399f360d807e2695bafd19793ec5 100644
--- a/include/aidge/backend/cpu.hpp
+++ b/include/aidge/backend/cpu.hpp
@@ -12,7 +12,6 @@
 #ifndef AIDGE_CPU_IMPORTS_H_
 #define AIDGE_CPU_IMPORTS_H_
 
-#include "aidge/backend/cpu/data/TensorImpl.hpp"
 #include "aidge/backend/cpu/operator/AddImpl.hpp"
 #include "aidge/backend/cpu/operator/AvgPoolingImpl.hpp"
 #include "aidge/backend/cpu/operator/MaxPoolingImpl.hpp"
@@ -40,4 +39,7 @@
 #include "aidge/backend/cpu/operator/SubImpl.hpp"
 #include "aidge/backend/cpu/operator/TransposeImpl.hpp"
 
-#endif /* AIDGE_CPU_IMPORTS_H_ */
\ No newline at end of file
+#include "aidge/backend/cpu/data/TensorImpl.hpp"
+
+#endif /* AIDGE_CPU_IMPORTS_H_ */
+
diff --git a/include/aidge/backend/cpu/data/GetCPUPtr.h b/include/aidge/backend/cpu/data/GetCPUPtr.h
deleted file mode 100644
index 335be9ca7ed1f2d0b3eeb71c8df34eda1ebece3f..0000000000000000000000000000000000000000
--- a/include/aidge/backend/cpu/data/GetCPUPtr.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/********************************************************************************
- * Copyright (c) 2023 CEA-List
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0.
- *
- * SPDX-License-Identifier: EPL-2.0
- *
- ********************************************************************************/
-
-#ifndef AIDGE_CPU_DATA_GETCPUPTR_H_
-#define AIDGE_CPU_DATA_GETCPUPTR_H_
-
-#include "aidge/data/Tensor.hpp"
-
-namespace Aidge {
-inline void *getCPUPtr(std::shared_ptr<Aidge::Data> const &data, const std::size_t offset = 0) {
-  const auto tensor = std::static_pointer_cast<Tensor>(data);
-  return tensor->getImpl()->hostPtr(tensor->getImplOffset() + offset);
-}
-} // namespace Aidge
-
-#endif // AIDGE_CPU_DATA_GETCPUPTR_H_
\ No newline at end of file
diff --git a/include/aidge/backend/cpu/data/TensorImpl.hpp b/include/aidge/backend/cpu/data/TensorImpl.hpp
deleted file mode 100644
index c9a0e6d2d3f76c523fd99c24339f6f4e78ce8e6e..0000000000000000000000000000000000000000
--- a/include/aidge/backend/cpu/data/TensorImpl.hpp
+++ /dev/null
@@ -1,200 +0,0 @@
-/********************************************************************************
- * Copyright (c) 2023 CEA-List
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0.
- *
- * SPDX-License-Identifier: EPL-2.0
- *
- ********************************************************************************/
-
-#ifndef AIDGE_CPU_DATA_TENSORIMPL_H_
-#define AIDGE_CPU_DATA_TENSORIMPL_H_
-
-#include "aidge/backend/TensorImpl.hpp"
-#include "aidge/data/Tensor.hpp"
-#include "aidge/data/half.hpp"
-#include "aidge/utils/Registrar.hpp"
-#include "aidge/utils/Types.h"
-#include "aidge/utils/ErrorHandling.hpp"
-#include "aidge/utils/future_std/span.hpp"
-
-namespace Aidge {
-
-template <class T>
-class TensorImpl_cpu : public TensorImpl {
-private:
-    /// Pointer to the data and its capacity
-    future_std::span<T> mData;
-    /// If this instance own the data, std::unique_ptr manages it
-    std::unique_ptr<T[]> mDataOwner;
-
-public:
-    static constexpr const char *Backend = "cpu";
-
-    TensorImpl_cpu(DeviceIdx_t device, std::vector<DimSize_t> dims) : TensorImpl(Backend, device, dims) {}
-
-    bool operator==(const TensorImpl &otherImpl) const override final {
-        const auto& typedOtherImpl = reinterpret_cast<const TensorImpl_cpu<T> &>(otherImpl);
-        AIDGE_INTERNAL_ASSERT(typedOtherImpl.size() >= mNbElts);
-
-        std::size_t i = 0;
-        for (; i < mNbElts &&
-               *(mData.data()+i) == *static_cast<const T*>(typedOtherImpl.rawPtr(i));
-               ++i) {
-        }
-        return i == mNbElts;
-    }
-
-    static std::shared_ptr<TensorImpl_cpu> create(DeviceIdx_t device, std::vector<DimSize_t> dims) {
-        return std::make_shared<TensorImpl_cpu<T>>(device, dims);
-    }
-
-    inline std::size_t scalarSize() const noexcept override final { return sizeof(T); }
-
-    void copy(const void *src, NbElts_t length, NbElts_t offset = 0) override final {
-        const T* srcT = static_cast<const T *>(src);
-        T* dstT = static_cast<T *>(rawPtr(offset));
-
-        AIDGE_ASSERT(length <= mData.size() || length <= mNbElts, "copy length is above capacity");
-        AIDGE_ASSERT(dstT < srcT || dstT >= srcT + length, "overlapping copy is not supported");
-        std::copy(srcT, srcT + length, dstT);
-    }
-
-    void copyCast(const void *src, const DataType srcDt, NbElts_t length, NbElts_t offset = 0) override final {
-        if (length == 0) {
-            return;
-        }
-
-        T* dstT = static_cast<T *>(rawPtr(offset));
-        AIDGE_ASSERT(length <= mData.size() || length <= mNbElts, "copy length is above capacity");
-        switch (srcDt)
-        {
-            case DataType::Float64:
-                std::copy(static_cast<const double*>(src), static_cast<const double*>(src) + length,
-                        dstT);
-                break;
-            case DataType::Float32:
-                std::copy(static_cast<const float*>(src), static_cast<const float*>(src) + length,
-                        dstT);
-                break;
-            case DataType::Float16:
-                std::copy(static_cast<const half_float::half*>(src), static_cast<const half_float::half*>(src) + length,
-                        dstT);
-                break;
-            case DataType::Int64:
-                std::copy(static_cast<const int64_t*>(src), static_cast<const int64_t*>(src) + length,
-                        dstT);
-                break;
-            case DataType::UInt64:
-                std::copy(static_cast<const uint64_t*>(src), static_cast<const uint64_t*>(src) + length,
-                        dstT);
-                break;
-            case DataType::Int32:
-                std::copy(static_cast<const int32_t*>(src), static_cast<const int32_t*>(src) + length,
-                        dstT);
-                break;
-            case DataType::UInt32:
-                std::copy(static_cast<const uint32_t*>(src), static_cast<const uint32_t*>(src) + length,
-                        dstT);
-                break;
-            case DataType::Int16:
-                std::copy(static_cast<const int16_t*>(src), static_cast<const int16_t*>(src) + length,
-                        dstT);
-                break;
-            case DataType::UInt16:
-                std::copy(static_cast<const uint16_t*>(src), static_cast<const uint16_t*>(src) + length,
-                        dstT);
-                break;
-            case DataType::Int8:
-                std::copy(static_cast<const int8_t*>(src), static_cast<const int8_t*>(src) + length,
-                        dstT);
-                break;
-            case DataType::UInt8:
-                std::copy(static_cast<const uint8_t*>(src), static_cast<const uint8_t*>(src) + length,
-                        dstT);
-                break;
-            default:
-                AIDGE_THROW_OR_ABORT(std::runtime_error, "Unsupported data type.");
-                break;
-        }
-    }
-
-    void copyFromDevice(const void *src, const std::pair<std::string, DeviceIdx_t>& device, NbElts_t length, NbElts_t offset = 0) override final {
-        AIDGE_ASSERT(device.first == Backend, "backend must match");
-        AIDGE_ASSERT(device.second == 0, "device cannot be != 0 for CPU backend");
-        copy(src, length, offset);
-    }
-
-    inline void copyFromHost(const void *src, NbElts_t length, NbElts_t offset = 0) override final {
-        copy(src, length, offset);
-    }
-
-    void copyToHost(void *dst, NbElts_t length, NbElts_t offset = 0) const override final {
-        const T* src = static_cast<const T*>(rawPtr(offset));
-        AIDGE_ASSERT(length <= mData.size() || length <= mNbElts, "copy length is above capacity");
-        std::copy(src, src + length, static_cast<T *>(dst));
-    }
-
-    void *rawPtr(NbElts_t offset = 0) override final {
-        lazyInit();
-        return (mData.data() + offset);
-    };
-
-    const void *rawPtr(NbElts_t offset = 0) const override final {
-        AIDGE_ASSERT(mData.size() >= mNbElts, "accessing uninitialized const rawPtr");
-        return (mData.data() + offset);
-    };
-
-    void *hostPtr(NbElts_t offset = 0) override final {
-        lazyInit();
-        return (mData.data() + offset);
-    };
-
-    const void *hostPtr(NbElts_t offset = 0) const override final {
-        AIDGE_ASSERT(mData.size() >= mNbElts, "accessing uninitialized const hostPtr");
-        return (mData.data() + offset);
-    };
-
-    void setRawPtr(void *ptr, NbElts_t length) override final {
-        AIDGE_ASSERT(length >= mNbElts, "trying to set raw pointer of insufficient capacity");
-        mData = future_std::span<T>(static_cast<T *>(ptr), length);
-        mDataOwner.reset();
-    };
-
-    virtual ~TensorImpl_cpu() = default;
-
-private:
-    void lazyInit() {
-        if (mData.size() < mNbElts) {
-            // Need more data, a re-allocation will occur
-            AIDGE_ASSERT(mData.empty() || mDataOwner != nullptr, "trying to enlarge non-owned data");
-            mDataOwner.reset(new T[mNbElts]);
-            mData = future_std::span<T>(mDataOwner.get(), mNbElts);
-        }
-    }
-};
-namespace {
-static Registrar<Tensor> registrarTensorImpl_cpu_Float64(
-        {"cpu", DataType::Float64}, Aidge::TensorImpl_cpu<double>::create);
-static Registrar<Tensor> registrarTensorImpl_cpu_Float32(
-        {"cpu", DataType::Float32}, Aidge::TensorImpl_cpu<float>::create);
-static Registrar<Tensor> registrarTensorImpl_cpu_Float16(
-        {"cpu", DataType::Float16}, Aidge::TensorImpl_cpu<half_float::half>::create);
-static Registrar<Tensor> registrarTensorImpl_cpu_Int64(
-        {"cpu", DataType::Int64}, Aidge::TensorImpl_cpu<long>::create);
-static Registrar<Tensor> registrarTensorImpl_cpu_Int32(
-        {"cpu", DataType::Int32}, Aidge::TensorImpl_cpu<int>::create);
-static Registrar<Tensor> registrarTensorImpl_cpu_Int16(
-        {"cpu", DataType::Int16}, Aidge::TensorImpl_cpu<int16_t>::create);
-static Registrar<Tensor> registrarTensorImpl_cpu_UInt16(
-        {"cpu", DataType::UInt16}, Aidge::TensorImpl_cpu<uint16_t>::create);
-static Registrar<Tensor> registrarTensorImpl_cpu_Int8(
-        {"cpu", DataType::Int8}, Aidge::TensorImpl_cpu<int8_t>::create);
-static Registrar<Tensor> registrarTensorImpl_cpu_UInt8(
-        {"cpu", DataType::UInt8}, Aidge::TensorImpl_cpu<uint8_t>::create);
-}  // namespace
-}  // namespace Aidge
-
-#endif /* AIDGE_CPU_DATA_TENSORIMPL_H_ */
diff --git a/unit_tests/data/Test_TensorImpl.cpp b/unit_tests/data/Test_TensorImpl.cpp
deleted file mode 100644
index 0f952c90eae47e26ccd95c5c479c6acf3495fc59..0000000000000000000000000000000000000000
--- a/unit_tests/data/Test_TensorImpl.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-/********************************************************************************
- * Copyright (c) 2023 CEA-List
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0.
- *
- * SPDX-License-Identifier: EPL-2.0
- *
- ********************************************************************************/
-
-#include <array>
-
-#include <catch2/catch_test_macros.hpp>
-
-#include "aidge/data/Tensor.hpp"
-#include "aidge/utils/TensorUtils.hpp"
-#include "aidge/backend/cpu/data/TensorImpl.hpp"
-
-using namespace Aidge;
-
-TEST_CASE("[backend_cpu/data] Tensor(constructor)","[Tensor]") {
-  SECTION("from const array") {
-    Tensor x = Array3D<int, 2, 2, 2>{{{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}};
-
-    Tensor xCopy = Array3D<int, 2, 2, 2>{{{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}};
-
-    Tensor xFloat =
-        Array3D<float, 2, 2, 2>{{{{1., 2.}, {3., 4.}}, {{5., 6.}, {7., 8.}}}};
-
-    SECTION("Tensor features") {
-      REQUIRE(x.nbDims() == 3);
-      REQUIRE(x.dims()[0] == 2);
-      REQUIRE(x.dims()[1] == 2);
-      REQUIRE(x.dims()[2] == 2);
-      REQUIRE(x.size() == 8);
-    }
-
-    SECTION("Access to array") {
-      REQUIRE(static_cast<int *>(x.getImpl()->rawPtr())[0] == 1);
-      REQUIRE(static_cast<int *>(x.getImpl()->rawPtr())[7] == 8);
-    }
-
-    SECTION("get function") {
-      REQUIRE(x.get<int>({0, 0, 0}) == 1);
-      REQUIRE(x.get<int>({0, 0, 1}) == 2);
-      REQUIRE(x.get<int>({0, 1, 1}) == 4);
-      REQUIRE(x.get<int>({1, 1, 0}) == 7);
-      x.set<int>({1, 1, 1}, 36);
-      REQUIRE(x.get<int>({1, 1, 1}) == 36);
-    }
-
-    SECTION("Pretty printing for debug") { REQUIRE_NOTHROW(x.print()); }
-
-    SECTION("Tensor (in)equality") {
-      REQUIRE(x == xCopy);
-      REQUIRE_FALSE(x == xFloat);
-    }
-  }
-}
-TEST_CASE("Tensor fill") {
-  SECTION("Instantiate batches independantly") {
-    // initialization with 0s
-    std::shared_ptr<Tensor> concatenatedTensor= std::make_shared<Tensor>(Array2D<int, 3, 5>{});
-    //concatenatedTensor->print();
-
-    std::shared_ptr<Tensor> myTensor1 = std::make_shared<Tensor>(Array1D<int, 5>{{1,2,3,4,5}});
-    std::shared_ptr<Tensor> myTensor2 = std::make_shared<Tensor>(Array1D<int, 5>{{6,7,8,9,10}});
-    std::shared_ptr<Tensor> myTensor3 = std::make_shared<Tensor>(Array1D<int, 5>{{11,12,13,14,15}});
-
-    // use copy function from implementation
-    concatenatedTensor->getImpl()->copy(myTensor1->getImpl()->rawPtr(), 5, 0);
-    concatenatedTensor->getImpl()->copy(myTensor2->getImpl()->rawPtr(), 5, 5);
-    concatenatedTensor->getImpl()->copy(myTensor3->getImpl()->rawPtr(), 5, 10);
-    // concatenatedTensor->print();
-
-    std::shared_ptr<Tensor> expectedTensor= std::make_shared<Tensor>(Array2D<int, 3, 5>{
-      {{1,2,3,4,5},
-      {6,7,8,9,10},
-      {11,12,13,14,15}}
-    });
-    // expectedTensor->print();
-
-    REQUIRE(*concatenatedTensor == *expectedTensor);
-  }
-}
-
-TEST_CASE("[backend_cpu/data] Tensor(methods)", "[Tensor]") {
-  Tensor x = Array3D<int, 2, 2, 2>{{
-    {{1, 2},
-     {3, 4}},
-    {{5, 6},
-     {7, 8}}
-  }};
-
-  Tensor xCopy = Array3D<int, 2, 2, 2>{{{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}};
-
-  Tensor xFloat =
-      Array3D<float, 2, 2, 2>{{{{1., 2.}, {3., 4.}}, {{5., 6.}, {7., 8.}}}};
-
-  SECTION("Tensor sharing") {
-    Tensor xCopyCtor(x);
-    REQUIRE(xCopyCtor.getImpl() == x.getImpl());
-
-    Tensor xEqOp = x;
-    REQUIRE(xEqOp.getImpl() == x.getImpl());
-
-    Tensor xCloned = x.clone();
-    REQUIRE(xCloned.getImpl() != x.getImpl());
-    REQUIRE(xCloned == x);
-  }
-
-  SECTION("Tensor extract") {
-    Tensor y = x.extract({0, 1});
-    REQUIRE(y.getImpl() == x.getImpl());
-    REQUIRE(approxEq<int>(y, Array1D<int, 2>{{3, 4}}));
-    REQUIRE(y.isContiguous());
-
-    Tensor y2 = x.extract({0, 1, 1}, {2, 1, 1});
-    REQUIRE(y2.getImpl() == x.getImpl());
-    REQUIRE(!y2.isContiguous());
-    Tensor y3 = y2.clone();
-    REQUIRE(y3.isContiguous());
-    REQUIRE(approxEq<int>(y3, Array3D<int, 2, 1, 1>{{{{4}}, {{8}}}}));
-  }
-}