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}}}})); - } -}