diff --git a/paddle/fluid/framework/tensor_util.cc b/paddle/fluid/framework/tensor_util.cc index 1a6fe7ded304e21796c946a85cbfc7a911977021..4730f6a4ec887a2ba8cbc6837a6f27c35b5f43dc 100644 --- a/paddle/fluid/framework/tensor_util.cc +++ b/paddle/fluid/framework/tensor_util.cc @@ -84,6 +84,12 @@ void TensorCopy(const Tensor& src, const platform::Place& dst_place, } #endif #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 platform::is_cpu_place(dst_place)) { 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, } #endif #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 platform::is_cpu_place(dst_place)) { memory::Copy(BOOST_GET_CONST(platform::CPUPlace, dst_place), dst_ptr, diff --git a/paddle/fluid/operators/assign_op.h b/paddle/fluid/operators/assign_op.h index ed4ba24a74bea2aaedbbef4908904e2696826290..001a18859618c3d9e7bd75867669850020666826 100644 --- a/paddle/fluid/operators/assign_op.h +++ b/paddle/fluid/operators/assign_op.h @@ -54,7 +54,7 @@ class AssignFunctor { out_rows.set_height(rows.height()); auto &t = rows.value(); auto *m = out_rows.mutable_value(); - framework::TensorCopy(t, dev_ctx_.GetPlace(), dev_ctx_, m); + framework::TensorCopy(t, t.place(), m); } template @@ -70,7 +70,7 @@ class AssignFunctor { framework::LoDTensor *out) const { if (lod_tensor.numel() == 0) return; 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()); } diff --git a/paddle/fluid/pybind/imperative.cc b/paddle/fluid/pybind/imperative.cc index 14e76ebd26304ee1c191f7fa265d8cc5c3fbca49..b5dad4034a5f34a9626886c5e2c0830e3c74b3ad 100644 --- a/paddle/fluid/pybind/imperative.cc +++ b/paddle/fluid/pybind/imperative.cc @@ -718,6 +718,54 @@ void BindImperative(py::module *m_ptr) { loss.clear_gradient() print("After clear_gradient {}".format(loss.grad)) )DOC") + .def("clone", + [](std::shared_ptr &self) { + const auto &tensor = self->Var().Get(); + 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( + 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", [](imperative::VarBase &self, const imperative::Tracer &tracer, bool retain_graph) { diff --git a/python/paddle/fluid/tests/unittests/test_var_base.py b/python/paddle/fluid/tests/unittests/test_var_base.py index f6ac6715f6748a7962f29a3002fb84cc4cbf3628..6d4258a426d05654f98faac21d80ffca58862f8c 100644 --- a/python/paddle/fluid/tests/unittests/test_var_base.py +++ b/python/paddle/fluid/tests/unittests/test_var_base.py @@ -55,6 +55,15 @@ class TestVarBase(unittest.TestCase): np.array_equal(x.numpy(), np.array([1.2]).astype( 'float32'))) 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 x = paddle.to_tensor(1 + 2j, place=place, stop_gradient=False) @@ -405,6 +414,7 @@ class TestVarBase(unittest.TestCase): self.assertListEqual(list(var_base.shape), list(static_var.shape)) def test_tensor_str(self): + paddle.enable_static() paddle.disable_static(paddle.CPUPlace()) paddle.manual_seed(10) a = paddle.rand([10, 20])