Skip to content

Commit

Permalink
make paddle.to_tensor() copy if data is varbase (#33335)
Browse files Browse the repository at this point in the history
* fix stop_gradient in paddle.to_tensor

* make to_tensor copy if data is varbase

* add ut

* refine sample code
  • Loading branch information
zhiqiu authored Jun 4, 2021
1 parent 57bdf32 commit 6877b13
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 24 deletions.
11 changes: 10 additions & 1 deletion python/paddle/fluid/tests/unittests/test_var_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,14 @@ def _test_place(place):
_test_place(core.CUDAPlace(0))
_test_place("gpu:0")

def test_to_tensor_not_change_input_stop_gradient(self):
with paddle.fluid.dygraph.guard(core.CPUPlace()):
a = paddle.zeros([1024])
a.stop_gradient = False
b = paddle.to_tensor(a)
self.assertEqual(a.stop_gradient, False)
self.assertEqual(b.stop_gradient, True)

def test_to_tensor_change_place(self):
if core.is_compiled_with_cuda():
a_np = np.random.rand(1024, 1024)
Expand Down Expand Up @@ -260,8 +268,9 @@ def test_to_tensor_with_lodtensor(self):
with paddle.fluid.dygraph.guard(core.CUDAPlace(0)):
lod_tensor = core.LoDTensor()
lod_tensor.set(a_np, core.CUDAPlace(0))
a = paddle.to_tensor(lod_tensor)
a = paddle.to_tensor(lod_tensor, place=core.CPUPlace())
self.assertTrue(np.array_equal(a_np, a.numpy()))
self.assertTrue(a.place.__repr__(), "CPUPlace")

def test_to_variable(self):
with fluid.dygraph.guard():
Expand Down
47 changes: 24 additions & 23 deletions python/paddle/tensor/creation.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,8 @@ def to_tensor(data, dtype=None, place=None, stop_gradient=True):
Constructs a ``paddle.Tensor`` from ``data`` ,
which can be scalar, tuple, list, numpy\.ndarray, paddle\.Tensor.
If the ``data`` is already a tensor, and ``dtype`` or ``place`` does't change, no copy
will be performed and return origin tensor, otherwise a new tensor will be constructed
and returned.
If the ``data`` is already a Tensor, copy will be performed and return a new tensor.
If you only want to change stop_gradient property, please call ``Tensor.stop_gradient = stop_gradient`` directly.
Args:
data(scalar|tuple|list|ndarray|Tensor): Initial data for the tensor.
Expand Down Expand Up @@ -75,32 +74,31 @@ def to_tensor(data, dtype=None, place=None, stop_gradient=True):
# <class 'paddle.Tensor'>
paddle.to_tensor(1)
# Tensor(shape=[1], dtype=int64, place=CUDAPlace(0), stop_gradient=True,
# Tensor(shape=[1], dtype=int64, place=CPUPlace, stop_gradient=True,
# [1])
x = paddle.to_tensor(1)
paddle.to_tensor(x, dtype='int32', place=paddle.CPUPlace()) # A new tensor will be constructed due to different dtype or place
# Tensor(shape=[1], dtype=int32, place=CPUPlace, stop_gradient=True,
x = paddle.to_tensor(1, stop_gradient=False)
print(x)
# Tensor(shape=[1], dtype=int64, place=CPUPlace, stop_gradient=False,
# [1])
paddle.to_tensor((1.1, 2.2), place=paddle.CUDAPinnedPlace())
# Tensor(shape=[1], dtype=float32, place=CUDAPinnedPlace, stop_gradient=True,
# [1])
paddle.to_tensor(x) # A new tensor will be created with default stop_gradient=True
# Tensor(shape=[1], dtype=int64, place=CPUPlace, stop_gradient=True,
# [1])
paddle.to_tensor([[0.1, 0.2], [0.3, 0.4]], place=paddle.CUDAPlace(0), stop_gradient=False)
# Tensor(shape=[2, 2], dtype=float32, place=CUDAPlace(0), stop_gradient=False,
paddle.to_tensor([[0.1, 0.2], [0.3, 0.4]], place=paddle.CPUPlace(), stop_gradient=False)
# Tensor(shape=[2, 2], dtype=float32, place=CPUPlace, stop_gradient=False,
# [[0.10000000, 0.20000000],
# [0.30000001, 0.40000001]])
type(paddle.to_tensor([[1+1j, 2], [3+2j, 4]], dtype='complex64'))
# <class 'paddle.VarBase'>
# <class 'paddle.Tensor'>
paddle.to_tensor([[1+1j, 2], [3+2j, 4]], dtype='complex64')
# Tensor(shape=[2, 2], dtype=complex64, place=CUDAPlace(0), stop_gradient=True,
# Tensor(shape=[2, 2], dtype=complex64, place=CPUPlace, stop_gradient=True,
# [[(1+1j), (2+0j)],
# [(3+2j), (4+0j)]])
"""

place = _get_paddle_place(place)
if place is None:
place = _current_expected_place()
Expand All @@ -119,10 +117,7 @@ def to_tensor(data, dtype=None, place=None, stop_gradient=True):

if not isinstance(data, np.ndarray):

def _handle_diff_place_dtype(data, dtype, place, stop_gradient):
data.stop_gradient = stop_gradient
if not data.place._equals(place):
data = data._copy_to(place, False)
def _handle_dtype(data, dtype):
if dtype:
if convert_dtype(dtype) != convert_dtype(data.dtype):
return data.astype(convert_dtype(dtype))
Expand All @@ -138,11 +133,17 @@ def _handle_diff_place_dtype(data, dtype, place, stop_gradient):
"this means the input data contains nested lists with different lengths. "
)
elif isinstance(data, paddle.Tensor):
return _handle_diff_place_dtype(data, dtype, place, stop_gradient)
elif isinstance(data, (core.Tensor, core.LoDTensor)):
# convert LoDTensor to VarBase first, and then process it as input VarBase
data = data._copy_to(place, False)
ata = _handle_dtype(data, dtype)
data.stop_gradient = stop_gradient
elif isinstance(data, core.LoDTensor):
# convert LoDTensor to VarBase first
# Currenly, LoDTensor does no copy when places are same
data = paddle.Tensor(data)
return _handle_diff_place_dtype(data, dtype, place, stop_gradient)
if not data.place._equals(place):
data = data._copy_to(place, False)
data = _handle_dtype(data, dtype)
data.stop_gradient = stop_gradient
else:
raise TypeError(
"Can't constructs a 'paddle.Tensor' with data type {}, data type must be scalar|list|tuple|numpy.ndarray|paddle.Tensor".
Expand Down

0 comments on commit 6877b13

Please sign in to comment.