diff options
author | Edward Yang <ezyang@fb.com> | 2019-01-29 07:11:47 -0800 |
---|---|---|
committer | Facebook Github Bot <facebook-github-bot@users.noreply.github.com> | 2019-01-29 07:14:57 -0800 |
commit | 3b337e7892a7b54758f273477aa092053f02b410 (patch) | |
tree | 897f20a521093da5dcc988c8ae574a98d681901c /aten | |
parent | bd19dd4b90aa94359b84986b0f9a298538ac7889 (diff) | |
download | pytorch-3b337e7892a7b54758f273477aa092053f02b410.tar.gz pytorch-3b337e7892a7b54758f273477aa092053f02b410.tar.bz2 pytorch-3b337e7892a7b54758f273477aa092053f02b410.zip |
Revert D13596031: Improve c2-aten tensor interop and add proper testing
Differential Revision:
D13596031
Original commit changeset: d20b601e06ba
fbshipit-source-id: dc371697f14b3893a9164380a39e7a49d8d68ecf
Diffstat (limited to 'aten')
-rw-r--r-- | aten/src/ATen/core/LegacyTypeDispatch.h | 17 | ||||
-rw-r--r-- | aten/src/ATen/core/Tensor.cpp | 21 | ||||
-rw-r--r-- | aten/src/ATen/core/Tensor.h | 27 | ||||
-rw-r--r-- | aten/src/ATen/templates/Tensor.h | 27 | ||||
-rw-r--r-- | aten/src/ATen/test/CMakeLists.txt | 3 | ||||
-rw-r--r-- | aten/src/ATen/test/cuda_tensor_interop_test.cpp | 164 | ||||
-rw-r--r-- | aten/src/ATen/test/tensor_interop_test.cpp | 190 | ||||
-rw-r--r-- | aten/src/THC/generic/THCTensorMathPointwise.cu | 2 | ||||
-rwxr-xr-x | aten/tools/run_tests.sh | 3 |
9 files changed, 54 insertions, 400 deletions
diff --git a/aten/src/ATen/core/LegacyTypeDispatch.h b/aten/src/ATen/core/LegacyTypeDispatch.h index 66bfcd65d5..9c9d44e84f 100644 --- a/aten/src/ATen/core/LegacyTypeDispatch.h +++ b/aten/src/ATen/core/LegacyTypeDispatch.h @@ -176,20 +176,9 @@ struct CAFFE2_API AutoNonVariableTypeMode { inline Type& legacyTensorType(const TensorImpl& tensor) { // NB: It's valid to use getTypeRaw here, because the TensorImpl // could not have been created without initializing the Type first. - // NB: This is not actually true via the Caffe2 codepath! But we call - // initializeLegacyTypeDispatchFor in the right place. - return *globalLegacyTypeDispatch().getTypeRaw( - tensorTypeIdToBackend(tensor.type_id()), - typeMetaToScalarType(tensor.dtype()), - tensor.is_variable() && !at::NonVariableTypeMode::is_enabled()); -} - -inline void initializeLegacyTypeDispatchFor(const TensorImpl& tensor) { - // getType calls the right initialization - globalLegacyTypeDispatch().getType( - tensorTypeIdToBackend(tensor.type_id()), - typeMetaToScalarType(tensor.dtype()), - tensor.is_variable() && !at::NonVariableTypeMode::is_enabled()); + // TODO: This is not actually true via the Caffe2 codepath! Make + // it so. + return *globalLegacyTypeDispatch().getTypeRaw(tensorTypeIdToBackend(tensor.type_id()), typeMetaToScalarType(tensor.dtype()), tensor.is_variable() && !at::NonVariableTypeMode::is_enabled()); } } // namespace at diff --git a/aten/src/ATen/core/Tensor.cpp b/aten/src/ATen/core/Tensor.cpp index a6489c0a4e..924688d40b 100644 --- a/aten/src/ATen/core/Tensor.cpp +++ b/aten/src/ATen/core/Tensor.cpp @@ -6,27 +6,6 @@ namespace at { -void Tensor::enforce_invariants() { - if (impl_.get() == nullptr) { - throw std::runtime_error("TensorImpl with nullptr is not supported"); - } - // Following line throws if the method is not a POD data type or is not - // supported by ATen - scalar_type(); - if (defined()) { - AT_ASSERTM( - impl_->dtype_initialized(), - "Partially-initialized tensor not supported by at::Tensor"); - AT_ASSERTM( - impl_->storage_initialized(), - "Partially-initialized tensor not supported by at::Tensor"); - // Ensure LegacyTypeDispatch is initialized. In ATen it's done in tensor - // factory functions, but when we get a tensor from Caffe2 we might bypass - // those factory functions. - initializeLegacyTypeDispatchFor(*impl_); - } -} - void Tensor::print() const { if (defined()) { std::cerr << "[" << type().toString() << " " << sizes() << "]" << std::endl; diff --git a/aten/src/ATen/core/Tensor.h b/aten/src/ATen/core/Tensor.h index ba4ccb4393..6abf5fcbe9 100644 --- a/aten/src/ATen/core/Tensor.h +++ b/aten/src/ATen/core/Tensor.h @@ -46,34 +46,20 @@ using TensorList = ArrayRef<Tensor>; // Note that Tensor can also be NULL, i.e. it is not associated with any underlying TensorImpl, and // special care must be taken to handle this. class CAFFE2_API Tensor { - public: +public: Tensor(){}; - // This constructor should not be used by end users and is an implementation - // detail invoked by autogenerated code. - explicit Tensor( - c10::intrusive_ptr<TensorImpl, UndefinedTensorImpl> tensor_impl) + Tensor(c10::intrusive_ptr<TensorImpl, UndefinedTensorImpl> tensor_impl) : impl_(std::move(tensor_impl)) { if (impl_.get() == nullptr) { - throw std::runtime_error("TensorImpl with nullptr is not supported"); + throw std::runtime_error("TensorBaseImpl with nullptr not supported"); } } + Tensor(const Tensor&) = default; Tensor(Tensor&&) = default; - - public: - // Creates a new wrapper from TensorImpl. Intentionally a free method because - // it should be used with care. Checks necessary invariants - static Tensor wrap_tensor_impl( - c10::intrusive_ptr<TensorImpl, UndefinedTensorImpl> tensor_impl) { - Tensor r(std::move(tensor_impl)); - r.enforce_invariants(); - return r; - } - - explicit Tensor(C10Tensor tensor) : impl_(std::move(tensor).impl()) { - enforce_invariants(); - } + explicit Tensor(C10Tensor tensor) + : impl_(std::move(tensor).impl()) {} explicit operator C10Tensor() const & { return C10Tensor(impl_); @@ -722,7 +708,6 @@ class CAFFE2_API Tensor { friend struct WeakTensor; protected: - void enforce_invariants(); c10::intrusive_ptr<TensorImpl, UndefinedTensorImpl> impl_; }; diff --git a/aten/src/ATen/templates/Tensor.h b/aten/src/ATen/templates/Tensor.h index ce69ef4bd5..fe0cd0c157 100644 --- a/aten/src/ATen/templates/Tensor.h +++ b/aten/src/ATen/templates/Tensor.h @@ -46,34 +46,20 @@ using TensorList = ArrayRef<Tensor>; // Note that Tensor can also be NULL, i.e. it is not associated with any underlying TensorImpl, and // special care must be taken to handle this. class CAFFE2_API Tensor { - public: +public: Tensor(){}; - // This constructor should not be used by end users and is an implementation - // detail invoked by autogenerated code. - explicit Tensor( - c10::intrusive_ptr<TensorImpl, UndefinedTensorImpl> tensor_impl) + Tensor(c10::intrusive_ptr<TensorImpl, UndefinedTensorImpl> tensor_impl) : impl_(std::move(tensor_impl)) { if (impl_.get() == nullptr) { - throw std::runtime_error("TensorImpl with nullptr is not supported"); + throw std::runtime_error("TensorBaseImpl with nullptr not supported"); } } + Tensor(const Tensor&) = default; Tensor(Tensor&&) = default; - - public: - // Creates a new wrapper from TensorImpl. Intentionally a free method because - // it should be used with care. Checks necessary invariants - static Tensor wrap_tensor_impl( - c10::intrusive_ptr<TensorImpl, UndefinedTensorImpl> tensor_impl) { - Tensor r(std::move(tensor_impl)); - r.enforce_invariants(); - return r; - } - - explicit Tensor(C10Tensor tensor) : impl_(std::move(tensor).impl()) { - enforce_invariants(); - } + explicit Tensor(C10Tensor tensor) + : impl_(std::move(tensor).impl()) {} explicit operator C10Tensor() const & { return C10Tensor(impl_); @@ -327,7 +313,6 @@ class CAFFE2_API Tensor { friend struct WeakTensor; protected: - void enforce_invariants(); c10::intrusive_ptr<TensorImpl, UndefinedTensorImpl> impl_; }; diff --git a/aten/src/ATen/test/CMakeLists.txt b/aten/src/ATen/test/CMakeLists.txt index 1d2457154b..d3f0d0134b 100644 --- a/aten/src/ATen/test/CMakeLists.txt +++ b/aten/src/ATen/test/CMakeLists.txt @@ -29,8 +29,7 @@ list(APPEND ATen_CUDA_TEST_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/cuda_stream_test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/cuda_half_test.cu ${CMAKE_CURRENT_SOURCE_DIR}/cuda_optional_test.cu - ${CMAKE_CURRENT_SOURCE_DIR}/cuda_packedtensoraccessor_test.cu - ${CMAKE_CURRENT_SOURCE_DIR}/cuda_tensor_interop_test.cpp) + ${CMAKE_CURRENT_SOURCE_DIR}/cuda_packedtensoraccessor_test.cu) if (CUDNN_FOUND) list(APPEND ATen_CUDA_TEST_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/cuda_cudnn_test.cpp) diff --git a/aten/src/ATen/test/cuda_tensor_interop_test.cpp b/aten/src/ATen/test/cuda_tensor_interop_test.cpp deleted file mode 100644 index 9877fd2e03..0000000000 --- a/aten/src/ATen/test/cuda_tensor_interop_test.cpp +++ /dev/null @@ -1,164 +0,0 @@ -#include "gtest/gtest.h" - -#include "ATen/ATen.h" -#include <ATen/cuda/CUDAContext.h> -#include <caffe2/core/init.h> -#include <caffe2/core/operator.h> -#include <caffe2/core/context_gpu.h> -#include <caffe2/utils/math.h> - -// dumbest possible copies -template<typename T> -T cuda_get(T* addr) { - T result; - CUDA_ENFORCE(cudaMemcpy(&result, addr, sizeof(T), cudaMemcpyDefault)); - return result; -} - -template<typename T> -void cuda_set(T* addr, T value) { - CUDA_ENFORCE(cudaMemcpy(addr, &value, sizeof(T), cudaMemcpyDefault)); -} - -TEST(CUDACaffe2ToPytorch, SimpleLegacy) { - if (!at::cuda::is_available()) return; - caffe2::Tensor c2_tensor(caffe2::CUDA); - c2_tensor.Resize(4, 4); - auto data = c2_tensor.mutable_data<int64_t>(); - { - caffe2::CUDAContext context; - caffe2::math::Set<int64_t>(16, 777, data, &context); - } - at::Tensor at_tensor(c2_tensor); - ASSERT_TRUE(&at_tensor.type() != nullptr); - ASSERT_TRUE(at_tensor.is_cuda()); - - auto at_cpu = at_tensor.cpu(); - auto it = at_cpu.data<int64_t>(); - for (int64_t i = 0; i < 16; i++) { - ASSERT_EQ(it[i], 777); - } -} - -TEST(CUDACaffe2ToPytorch, Simple) { - if (!at::cuda::is_available()) return; - caffe2::Tensor c2_tensor = - caffe2::empty({4, 4}, at::dtype<int64_t>().device(caffe2::CUDA)); - auto data = c2_tensor.mutable_data<int64_t>(); - { - caffe2::CUDAContext context; - caffe2::math::Set<int64_t>(16, 777, data, &context); - } - at::Tensor at_tensor(c2_tensor); - ASSERT_TRUE(&at_tensor.type() != nullptr); - ASSERT_TRUE(at_tensor.is_cuda()); - - auto at_cpu = at_tensor.cpu(); - auto it = at_cpu.data<int64_t>(); - for (int64_t i = 0; i < 16; i++) { - ASSERT_EQ(it[i], 777); - } -} - -TEST(CUDACaffe2ToPytorch, Op) { - if (!at::cuda::is_available()) return; - caffe2::Tensor c2_tensor = - caffe2::empty({3, 3}, at::dtype<int64_t>().device(caffe2::CUDA)); - auto data = c2_tensor.mutable_data<int64_t>(); - { - caffe2::CUDAContext context; - caffe2::math::Set<int64_t>(9, 111, data, &context); - } - at::Tensor at_tensor(c2_tensor); - ASSERT_TRUE(at_tensor.is_cuda()); - - ASSERT_EQ(at::sum(at_tensor).item<int64_t>(), 999); -} - -TEST(CUDAPytorchToCaffe2, Op) { - if (!at::cuda::is_available()) return; - caffe2::Workspace workspace; - caffe2::NetDef net; - - auto at_tensor_a = at::ones({5, 5}, at::dtype(at::kFloat).device(at::kCUDA)); - auto at_tensor_b = at::ones({5, 5}, at::dtype(at::kFloat).device(at::kCUDA)); - auto at_tensor_c = at::ones({5, 5}, at::dtype(at::kFloat).device(at::kCUDA)); - - auto* c2_tensor_a = BlobSetTensor(workspace.CreateBlob("a"), caffe2::Tensor(at_tensor_a)); - auto* c2_tensor_b = BlobSetTensor(workspace.CreateBlob("b"), caffe2::Tensor(at_tensor_b)); - - // Test Alias - { - caffe2::Tensor c2_tensor_from_aten(at_tensor_c); - BlobSetTensor(workspace.CreateBlob("c"), c2_tensor_from_aten.Alias()); - } - - { - auto op = net.add_op(); - op->set_type("Sum"); - op->add_input("a"); - op->add_input("b"); - op->add_input("c"); - op->add_output("d"); - op->mutable_device_option()->set_device_type(caffe2::PROTO_CUDA); - } - - workspace.RunNetOnce(net); - - const auto& result = workspace.GetBlob("d")->Get<caffe2::Tensor>(); - ASSERT_EQ(result.GetDeviceType(), caffe2::CUDA); - - auto data = result.data<float>(); - for (int64_t i = 0; i < 25; i++) { - ASSERT_EQ(cuda_get(data + i), 3.0); - } - at::Tensor at_result(result); - ASSERT_TRUE(at_result.is_cuda()); - ASSERT_EQ(at::sum(at_result).item<float>(), 75); -} - -TEST(CUDAPytorchToCaffe2, SharedStorageWrite) { - if (!at::cuda::is_available()) return; - auto at_tensor_a = at::ones({5, 5}, at::dtype(at::kFloat).device(at::kCUDA)); - auto at_tensor_b = at_tensor_a.view({25}); - - caffe2::Tensor c2_tensor_a(at_tensor_a); - caffe2::Tensor c2_tensor_b(at_tensor_b); - - // change is visible everywhere - cuda_set<float>(c2_tensor_a.mutable_data<float>() + 1, 123); - ASSERT_EQ(cuda_get(c2_tensor_b.mutable_data<float>() + 1), 123); - ASSERT_EQ(at_tensor_a[0][1].item().to<float>(), 123); - ASSERT_EQ(at_tensor_b[1].item().to<float>(), 123); -} - -TEST(CUDAPytorchToCaffe2, MutualResizes) { - if (!at::cuda::is_available()) return; - auto at_tensor = at::ones({5, 5}, at::dtype(at::kFloat).device(at::kCUDA)); - - caffe2::Tensor c2_tensor(at_tensor); - - // change is visible - cuda_set<float>(c2_tensor.mutable_data<float>(), 123); - ASSERT_EQ(at_tensor[0][0].item().to<float>(), 123); - - // resize PT tensor in smaller direction - storage is preserved - at_tensor.resize_({4, 4}); - cuda_set<float>(c2_tensor.mutable_data<float>() + 1, 234); - ASSERT_EQ(at_tensor[0][1].item().to<float>(), 234); - - // resize PT tensor in larger direction - storage is preserved - at_tensor.resize_({6, 6}); - cuda_set<float>(c2_tensor.mutable_data<float>() + 2, 345); - ASSERT_EQ(at_tensor[0][2].item().to<float>(), 345); - ASSERT_EQ(c2_tensor.sizes()[0], 6); - ASSERT_EQ(c2_tensor.sizes()[1], 6); - - // resize Caffe2 tensor - semantics are to NOT preserve the data, but the - // TensorImpl is still shared - c2_tensor.Resize(7, 7); - cuda_set<float>(c2_tensor.mutable_data<float>() + 3, 456); - ASSERT_EQ(at_tensor[0][3].item().to<float>(), 456); - ASSERT_EQ(at_tensor.sizes()[0], 7); - ASSERT_EQ(at_tensor.sizes()[1], 7); -} diff --git a/aten/src/ATen/test/tensor_interop_test.cpp b/aten/src/ATen/test/tensor_interop_test.cpp index 6016142db1..f926312b5f 100644 --- a/aten/src/ATen/test/tensor_interop_test.cpp +++ b/aten/src/ATen/test/tensor_interop_test.cpp @@ -4,83 +4,58 @@ #include <caffe2/core/init.h> #include <caffe2/core/operator.h> -TEST(Caffe2ToPytorch, SimpleLegacy) { +TEST(TestTensorInterop, Caffe2ToPytorchSimpleLegacy) { caffe2::Tensor c2_tensor(caffe2::CPU); c2_tensor.Resize(4, 4); auto data = c2_tensor.mutable_data<int64_t>(); for (int64_t i = 0; i < 16; i++) { data[i] = i; } - at::Tensor at_tensor(c2_tensor); - ASSERT_TRUE(&at_tensor.type() != nullptr); - auto it = at_tensor.data<int64_t>(); + // TODO: find out why calling data on tensor doesn't work + at::Tensor at_tensor(c2_tensor.getIntrusivePtr()); + at::TensorImpl* impl = at_tensor.unsafeGetTensorImpl(); + + auto it = impl->data<int64_t>(); for (int64_t i = 0; i < 16; i++) { ASSERT_EQ(it[i], i); } } -TEST(Caffe2ToPytorch, Simple) { +TEST(TestTensorInterop, Caffe2ToPytorchSimple) { caffe2::Tensor c2_tensor = caffe2::empty({4, 4}, at::kLong); auto data = c2_tensor.mutable_data<int64_t>(); for (int64_t i = 0; i < 16; i++) { data[i] = i; } - at::Tensor at_tensor(c2_tensor); - ASSERT_TRUE(&at_tensor.type() != nullptr); + at::Tensor at_tensor(c2_tensor.getIntrusivePtr()); + at::TensorImpl* impl = at_tensor.unsafeGetTensorImpl(); - auto it = at_tensor.data<int64_t>(); + auto it = impl->data<int64_t>(); for (int64_t i = 0; i < 16; i++) { ASSERT_EQ(it[i], i); } } -TEST(Caffe2ToPytorch, Op) { +TEST(TestTensorInterop, Caffe2ToPytorchOp) { caffe2::Tensor c2_tensor(caffe2::CPU); c2_tensor.Resize(3, 3); auto data = c2_tensor.mutable_data<int64_t>(); for (int64_t i = 0; i < 9; i++) { data[i] = i; } - at::Tensor at_tensor(c2_tensor); + at::Tensor at_tensor(c2_tensor.getIntrusivePtr()); ASSERT_EQ(at::sum(at_tensor).item<int64_t>(), 36); } -// Caffe2 doesn't actually have another always-on backend that is not CPU or GPU -// TEST(Caffe2ToPytorch, UnsupportedDevice) { -// caffe2::Tensor c2_tensor(caffe2::OPENGL); -// c2_tensor.Resize(4, 4); -// c2_tensor.mutable_data<float>(); -// at::Tensor at_tensor(c2_tensor); -// ASSERT_ANY_THROW(at::sum(at_tensor)); -// } - -TEST(Caffe2ToPytorch, PartiallyInitialized) { - // These APIs for partially initialized tensors should go away soon, in the - // meantime ensure they are caught - { - // no dtype, no storage - caffe2::Tensor c2_tensor(caffe2::CPU); - ASSERT_ANY_THROW(at::Tensor at_tensor(c2_tensor)); - } - { - // storage, no dtype - caffe2::Tensor c2_tensor(caffe2::CPU); - c2_tensor.Resize(4,4); - ASSERT_ANY_THROW(at::Tensor at_tensor(c2_tensor)); - } - { - // dtype, no storage - caffe2::Tensor c2_tensor(caffe2::CPU); - c2_tensor.Resize(4,4); - c2_tensor.mutable_data<float>(); - c2_tensor.FreeMemory(); - ASSERT_ANY_THROW(at::Tensor at_tensor(c2_tensor)); - } +TEST(TestTensorInterop, Caffe2ToPytorchUnsupportedDevice) { + caffe2::Tensor c2_tensor(caffe2::IDEEP); + at::Tensor at_tensor(c2_tensor.getIntrusivePtr()); + ASSERT_ANY_THROW(at::sum(at_tensor)); } -TEST(PytorchToCaffe2, Op) { +TEST(TestTensorInterop, PytorchToCaffe2Op) { caffe2::Workspace workspace; caffe2::NetDef net; @@ -88,13 +63,14 @@ TEST(PytorchToCaffe2, Op) { auto at_tensor_b = at::ones({5, 5}, at::dtype(at::kFloat)); auto at_tensor_c = at::ones({5, 5}, at::dtype(at::kFloat)); - auto* c2_tensor_a = BlobSetTensor(workspace.CreateBlob("a"), caffe2::Tensor(at_tensor_a)); - auto* c2_tensor_b = BlobSetTensor(workspace.CreateBlob("b"), caffe2::Tensor(at_tensor_b)); + auto* c2_tensor_a = BlobSetTensor(workspace.CreateBlob("a"), at_tensor_a.getIntrusivePtr()); + auto* c2_tensor_b = BlobSetTensor(workspace.CreateBlob("b"), at_tensor_b.getIntrusivePtr()); // Test Alias { - caffe2::Tensor c2_tensor_from_aten(at_tensor_c); + caffe2::Tensor c2_tensor_from_aten(at_tensor_c.getIntrusivePtr()); BlobSetTensor(workspace.CreateBlob("c"), c2_tensor_from_aten.Alias()); + } { @@ -114,19 +90,19 @@ TEST(PytorchToCaffe2, Op) { for (int64_t i = 0; i < 25; i++) { ASSERT_EQ(it[i], 3.0); } - at::Tensor at_result(result); + at::Tensor at_result(result.getIntrusivePtr()); ASSERT_EQ(at::sum(at_result).item<float>(), 75); } -TEST(PytorchToCaffe2, SharedStorageRead) { +TEST(TestTensorInterop, PytorchToCaffe2SharedStorage) { caffe2::Workspace workspace; caffe2::NetDef net; auto at_tensor_a = at::ones({5, 5}, at::dtype(at::kFloat)); auto at_tensor_b = at_tensor_a.view({5, 5}); - auto* c2_tensor_a = BlobSetTensor(workspace.CreateBlob("a"), caffe2::Tensor(at_tensor_a)); - auto* c2_tensor_b = BlobSetTensor(workspace.CreateBlob("b"), caffe2::Tensor(at_tensor_b)); + auto* c2_tensor_a = BlobSetTensor(workspace.CreateBlob("a"), at_tensor_a.getIntrusivePtr()); + auto* c2_tensor_b = BlobSetTensor(workspace.CreateBlob("b"), at_tensor_b.getIntrusivePtr()); { auto op = net.add_op(); @@ -143,115 +119,23 @@ TEST(PytorchToCaffe2, SharedStorageRead) { for (int64_t i = 0; i < 25; i++) { ASSERT_EQ(it[i], 2.0); } - at::Tensor at_result(result); + at::Tensor at_result(result.getIntrusivePtr()); ASSERT_EQ(at::sum(at_result).item<float>(), 50); } -TEST(PytorchToCaffe2, SharedStorageWrite) { - auto at_tensor_a = at::ones({5, 5}, at::dtype(at::kFloat)); - auto at_tensor_b = at_tensor_a.view({25}); - - caffe2::Tensor c2_tensor_a(at_tensor_a); - caffe2::Tensor c2_tensor_b(at_tensor_b); - - // change is visible everywhere - c2_tensor_a.mutable_data<float>()[1] = 123; - ASSERT_EQ(c2_tensor_b.mutable_data<float>()[1], 123); - ASSERT_EQ(at_tensor_a[0][1].item().to<float>(), 123); - ASSERT_EQ(at_tensor_b[1].item().to<float>(), 123); -} - -TEST(PytorchToCaffe2, MutualResizes) { - auto at_tensor = at::ones({5, 5}, at::dtype(at::kFloat)); - - caffe2::Tensor c2_tensor(at_tensor); - - // change is visible - c2_tensor.mutable_data<float>()[0] = 123; - ASSERT_EQ(at_tensor[0][0].item().to<float>(), 123); - - // resize PT tensor in smaller direction - storage is preserved - at_tensor.resize_({4, 4}); - c2_tensor.mutable_data<float>()[1] = 234; - ASSERT_EQ(at_tensor[0][1].item().to<float>(), 234); - - // resize PT tensor in larger direction - storage is preserved - at_tensor.resize_({6, 6}); - c2_tensor.mutable_data<float>()[2] = 345; - ASSERT_EQ(at_tensor[0][2].item().to<float>(), 345); - ASSERT_EQ(c2_tensor.sizes()[0], 6); - ASSERT_EQ(c2_tensor.sizes()[1], 6); - - // resize Caffe2 tensor - semantics are to NOT preserve the data, but the - // TensorImpl is still shared - c2_tensor.Resize(7, 7); - c2_tensor.mutable_data<float>()[3] = 456; - ASSERT_EQ(at_tensor[0][3].item().to<float>(), 456); - ASSERT_EQ(at_tensor.sizes()[0], 7); - ASSERT_EQ(at_tensor.sizes()[1], 7); -} +TEST(TestTensorInterop, PytorchToCaffe2Strided) { + caffe2::Workspace workspace; + caffe2::NetDef net; -TEST(PytorchToCaffe2, Strided) { auto at_tensor = at::ones({5, 5}, at::dtype(at::kFloat)).t(); - ASSERT_ANY_THROW(caffe2::Tensor c2_tensor(at_tensor)); - // but calling contiguous is fine - caffe2::Tensor c2_tensor(at_tensor.contiguous()); - for (int64_t i = 0; i < 25; i++) { - ASSERT_EQ(c2_tensor.data<float>()[i], 1.0); - } -} + auto* c2_tensor = BlobSetTensor(workspace.CreateBlob("blob"), at_tensor.getIntrusivePtr()); -TEST(PytorchToCaffe2, InplaceStrided) { - auto at_tensor = at::zeros({2, 5}, at::dtype(at::kFloat)); - caffe2::Tensor c2_tensor(at_tensor); - ASSERT_EQ(c2_tensor.sizes()[0], 2); - ASSERT_EQ(c2_tensor.sizes()[1], 5); - - c2_tensor.mutable_data<float>()[1] = 234; - ASSERT_EQ(at_tensor[0][1].item().to<float>(), 234); - - at_tensor.t_(); - ASSERT_EQ(c2_tensor.sizes()[0], 5); - ASSERT_EQ(c2_tensor.sizes()[1], 2); - // This is BROKEN situation, however checking is_contiguous on every data - // access is expensive. We rely on user to not do crazy stuff. - ASSERT_EQ(at_tensor[1][0].item().to<float>(), 234); - ASSERT_EQ(c2_tensor.data<float>()[1], 234); -} - -TEST(PytorchToCaffe2, NonRegularTensor) { - at::Tensor at_tensor = - at::empty({2, 3}, at::dtype<float>().layout(at::kSparse)); - ASSERT_TRUE(at_tensor.is_sparse()); - ASSERT_ANY_THROW(caffe2::Tensor c2_tensor(at_tensor)); -} - -// With current build system it's too bothersome to set it up, but the test -// passes -// TEST(PytorchToCaffe2, Variable) { -// at::Tensor var = -// torch::autograd::make_variable(at::empty({2, 3}, at::dtype<float>())); -// ASSERT_TRUE(var.is_variable()); -// ASSERT_ANY_THROW(caffe2::Tensor c2_tensor(var)); -// } - -TEST(Caffe2ToPytorch, NonPOD) { - caffe2::Tensor c2_tensor = caffe2::empty({1}, at::dtype<std::string>()); - auto data = c2_tensor.mutable_data<std::string>(); - *data = "test"; - ASSERT_ANY_THROW(at::Tensor at_tensor(c2_tensor)); -} - -TEST(Caffe2ToPytorch, Nullptr) { - caffe2::Tensor c2_tensor; - ASSERT_FALSE(c2_tensor.defined()); - at::Tensor at_tensor(c2_tensor); - ASSERT_FALSE(at_tensor.defined()); -} + { + auto op = net.add_op(); + op->set_type("Sum"); + op->add_input("blob"); + op->add_output("out"); + } -TEST(PytorchToCaffe2, Nullptr) { - at::Tensor at_tensor; - ASSERT_FALSE(at_tensor.defined()); - caffe2::Tensor c2_tensor(at_tensor); - ASSERT_FALSE(c2_tensor.defined()); + ASSERT_ANY_THROW(workspace.RunNetOnce(net)); } diff --git a/aten/src/THC/generic/THCTensorMathPointwise.cu b/aten/src/THC/generic/THCTensorMathPointwise.cu index 82fdd2ac1d..e3ef097515 100644 --- a/aten/src/THC/generic/THCTensorMathPointwise.cu +++ b/aten/src/THC/generic/THCTensorMathPointwise.cu @@ -241,7 +241,7 @@ void THCTensor_(cadd)(THCState *state, THCTensor *self_, THCTensor* src1, scalar #else auto alpha = value; #endif - at::add_out(out, at::Tensor(retainTensorImpl(src1)), at::Tensor(retainTensorImpl(src2)), alpha); + at::add_out(out, retainTensorImpl(src1), retainTensorImpl(src2), alpha); } void THCTensor_(csub)(THCState *state, THCTensor *self_, THCTensor* src1, scalar_t value, THCTensor *src2) diff --git a/aten/tools/run_tests.sh b/aten/tools/run_tests.sh index 8ed5a21e2d..c2a0d2f47f 100755 --- a/aten/tools/run_tests.sh +++ b/aten/tools/run_tests.sh @@ -35,9 +35,6 @@ fi if [[ -x ./cuda_optional_test ]]; then ./cuda_optional_test fi -if [[ -x ./cuda_tensor_interop_test ]]; then - ./cuda_tensor_interop_test -fi if [ "$VALGRIND" == "ON" ] then valgrind --suppressions="$VALGRIND_SUP" --error-exitcode=1 ./basic "[cpu]" |