summaryrefslogtreecommitdiff
path: root/aten
diff options
context:
space:
mode:
authorEdward Yang <ezyang@fb.com>2019-01-29 07:11:47 -0800
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>2019-01-29 07:14:57 -0800
commit3b337e7892a7b54758f273477aa092053f02b410 (patch)
tree897f20a521093da5dcc988c8ae574a98d681901c /aten
parentbd19dd4b90aa94359b84986b0f9a298538ac7889 (diff)
downloadpytorch-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.h17
-rw-r--r--aten/src/ATen/core/Tensor.cpp21
-rw-r--r--aten/src/ATen/core/Tensor.h27
-rw-r--r--aten/src/ATen/templates/Tensor.h27
-rw-r--r--aten/src/ATen/test/CMakeLists.txt3
-rw-r--r--aten/src/ATen/test/cuda_tensor_interop_test.cpp164
-rw-r--r--aten/src/ATen/test/tensor_interop_test.cpp190
-rw-r--r--aten/src/THC/generic/THCTensorMathPointwise.cu2
-rwxr-xr-xaten/tools/run_tests.sh3
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]"