未验证 提交 b57254ed 编写于 作者: Z Zhou Wei 提交者: GitHub

[cherry-pick2.0]Add tensor clone 2.0 (#27982)

* add tensor clone (#27953)

* add tensor clone

* fix unittest test_var_base

* fix bug of tensor copy of CUDAPinnedPlace (#27966)
上级 c0061ff5
...@@ -84,6 +84,12 @@ void TensorCopy(const Tensor& src, const platform::Place& dst_place, ...@@ -84,6 +84,12 @@ void TensorCopy(const Tensor& src, const platform::Place& dst_place,
} }
#endif #endif
#ifdef PADDLE_WITH_CUDA #ifdef PADDLE_WITH_CUDA
else if (platform::is_cuda_pinned_place(src_place) && // NOLINT
platform::is_cuda_pinned_place(dst_place)) {
memory::Copy(BOOST_GET_CONST(platform::CUDAPinnedPlace, dst_place), dst_ptr,
BOOST_GET_CONST(platform::CUDAPinnedPlace, src_place), src_ptr,
size);
}
else if (platform::is_cuda_pinned_place(src_place) && // NOLINT else if (platform::is_cuda_pinned_place(src_place) && // NOLINT
platform::is_cpu_place(dst_place)) { platform::is_cpu_place(dst_place)) {
memory::Copy(BOOST_GET_CONST(platform::CPUPlace, dst_place), dst_ptr, memory::Copy(BOOST_GET_CONST(platform::CPUPlace, dst_place), dst_ptr,
...@@ -285,6 +291,12 @@ void TensorCopySync(const Tensor& src, const platform::Place& dst_place, ...@@ -285,6 +291,12 @@ void TensorCopySync(const Tensor& src, const platform::Place& dst_place,
} }
#endif #endif
#ifdef PADDLE_WITH_CUDA #ifdef PADDLE_WITH_CUDA
else if (platform::is_cuda_pinned_place(src_place) && // NOLINT
platform::is_cuda_pinned_place(dst_place)) {
memory::Copy(BOOST_GET_CONST(platform::CUDAPinnedPlace, dst_place), dst_ptr,
BOOST_GET_CONST(platform::CUDAPinnedPlace, src_place), src_ptr,
size);
}
else if (platform::is_cuda_pinned_place(src_place) && // NOLINT else if (platform::is_cuda_pinned_place(src_place) && // NOLINT
platform::is_cpu_place(dst_place)) { platform::is_cpu_place(dst_place)) {
memory::Copy(BOOST_GET_CONST(platform::CPUPlace, dst_place), dst_ptr, memory::Copy(BOOST_GET_CONST(platform::CPUPlace, dst_place), dst_ptr,
......
...@@ -54,7 +54,7 @@ class AssignFunctor { ...@@ -54,7 +54,7 @@ class AssignFunctor {
out_rows.set_height(rows.height()); out_rows.set_height(rows.height());
auto &t = rows.value(); auto &t = rows.value();
auto *m = out_rows.mutable_value(); auto *m = out_rows.mutable_value();
framework::TensorCopy(t, dev_ctx_.GetPlace(), dev_ctx_, m); framework::TensorCopy(t, t.place(), m);
} }
template <typename T> template <typename T>
...@@ -70,7 +70,7 @@ class AssignFunctor { ...@@ -70,7 +70,7 @@ class AssignFunctor {
framework::LoDTensor *out) const { framework::LoDTensor *out) const {
if (lod_tensor.numel() == 0) return; if (lod_tensor.numel() == 0) return;
auto &out_tensor = *out; auto &out_tensor = *out;
TensorCopy(lod_tensor, dev_ctx_.GetPlace(), dev_ctx_, &out_tensor); TensorCopy(lod_tensor, lod_tensor.place(), &out_tensor);
out_tensor.set_lod(lod_tensor.lod()); out_tensor.set_lod(lod_tensor.lod());
} }
......
...@@ -718,6 +718,54 @@ void BindImperative(py::module *m_ptr) { ...@@ -718,6 +718,54 @@ void BindImperative(py::module *m_ptr) {
loss.clear_gradient() loss.clear_gradient()
print("After clear_gradient {}".format(loss.grad)) print("After clear_gradient {}".format(loss.grad))
)DOC") )DOC")
.def("clone",
[](std::shared_ptr<imperative::VarBase> &self) {
const auto &tensor = self->Var().Get<framework::LoDTensor>();
PADDLE_ENFORCE_EQ(
tensor.IsInitialized(), true,
platform::errors::InvalidArgument(
"%s has not been initialized", self->Name()));
auto tracer = imperative::GetCurrentTracer();
auto new_var = std::make_shared<imperative::VarBase>(
true, tracer->GenerateUniqueName(self->Name() + "_clone"));
framework::AttributeMap attrs;
imperative::NameVarBaseMap ins = {{"X", {self}}};
imperative::NameVarBaseMap outs = {{"Out", {new_var}}};
tracer->TraceOp("assign", ins, outs, attrs);
return new_var;
},
py::return_value_policy::copy, R"DOC(
Returns a new Tensor, which is clone of origin Tensor, and it remains in the current graph.
It will always have a Tensor copy.
Tn addition, the cloned Tensor provides gradient propagation.
Returns: The cloned Tensor.
Examples:
.. code-block:: python
import paddle
x = paddle.to_tensor(1.0, stop_gradient=False)
clone_x = x.clone()
y = clone_x**2
y.backward()
print(clone_x.stop_gradient) # False
print(clone_x.grad) # [2.0], support gradient propagation
print(x.stop_gradient) # False
print(x.grad) # [2.0], clone_x support gradient propagation for x
x = paddle.to_tensor(1.0)
clone_x = x.clone()
clone_x.stop_gradient = False
z = clone_x**3
z.backward()
print(clone_x.stop_gradient) # False
print(clone_x.grad) # [3.0], support gradient propagation
print(x.stop_gradient) # True
print(x.grad) # None
)DOC")
.def("_run_backward", .def("_run_backward",
[](imperative::VarBase &self, const imperative::Tracer &tracer, [](imperative::VarBase &self, const imperative::Tracer &tracer,
bool retain_graph) { bool retain_graph) {
......
...@@ -55,6 +55,15 @@ class TestVarBase(unittest.TestCase): ...@@ -55,6 +55,15 @@ class TestVarBase(unittest.TestCase):
np.array_equal(x.numpy(), np.array([1.2]).astype( np.array_equal(x.numpy(), np.array([1.2]).astype(
'float32'))) 'float32')))
self.assertEqual(x.dtype, core.VarDesc.VarType.FP32) self.assertEqual(x.dtype, core.VarDesc.VarType.FP32)
clone_x = x.clone()
self.assertTrue(
np.array_equal(clone_x.numpy(),
np.array([1.2]).astype('float32')))
self.assertEqual(clone_x.dtype, core.VarDesc.VarType.FP32)
y = clone_x**2
y.backward()
self.assertTrue(
np.array_equal(x.grad, np.array([2.4]).astype('float32')))
# set_default_dtype take effect on complex # set_default_dtype take effect on complex
x = paddle.to_tensor(1 + 2j, place=place, stop_gradient=False) x = paddle.to_tensor(1 + 2j, place=place, stop_gradient=False)
...@@ -405,6 +414,7 @@ class TestVarBase(unittest.TestCase): ...@@ -405,6 +414,7 @@ class TestVarBase(unittest.TestCase):
self.assertListEqual(list(var_base.shape), list(static_var.shape)) self.assertListEqual(list(var_base.shape), list(static_var.shape))
def test_tensor_str(self): def test_tensor_str(self):
paddle.enable_static()
paddle.disable_static(paddle.CPUPlace()) paddle.disable_static(paddle.CPUPlace())
paddle.manual_seed(10) paddle.manual_seed(10)
a = paddle.rand([10, 20]) a = paddle.rand([10, 20])
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册