From 1b9a3bfc9bd1e7e16e842e3f34cb9ca5a9249c93 Mon Sep 17 00:00:00 2001 From: Huihuang Zheng Date: Mon, 26 Apr 2021 10:17:49 +0800 Subject: [PATCH] [Dy2stat] Support paddle.to_tensor with int, float, bool. (#32420) paddle.to_tensor will be translated to paddle.assign in Dy2stat, however paddle.assign doesn't support int, float, bool. This PR added the supports. --- python/paddle/fluid/layers/tensor.py | 22 +++++++++++++--- .../test_basic_api_transformation.py | 22 +++++++++++++++- .../fluid/tests/unittests/test_assign_op.py | 25 ++++++++++++++----- .../tests/unittests/xpu/test_assign_op_xpu.py | 5 +--- python/paddle/tensor/creation.py | 7 +++--- 5 files changed, 64 insertions(+), 17 deletions(-) diff --git a/python/paddle/fluid/layers/tensor.py b/python/paddle/fluid/layers/tensor.py index d842c63047b..3e2c06f69cf 100644 --- a/python/paddle/fluid/layers/tensor.py +++ b/python/paddle/fluid/layers/tensor.py @@ -547,8 +547,10 @@ def assign(input, output=None): The OP copies the :attr:`input` to the :attr:`output`. Parameters: - input (Tensor|numpy.ndarray): A tensor or numpy ndarray, its data type supports - float16, float32, float64, int32 and int64. + input (Tensor|numpy.ndarray|list|tuple|scalar): A tensor, numpy ndarray, tuple/list of scalar, + or scalar. Its data type supports float16, float32, float64, int32, int64, and bool. + Note: the float64 data will be converted to float32 because of current platform protobuf + data limitation. output (Tensor, optional): A tensor. If :attr:`output` is None, a new tensor will be created as :attr:`output`. Default: None. @@ -570,9 +572,15 @@ def assign(input, output=None): result3 = paddle.assign(np.array([[2.5, 2.5], [2.5, 2.5], [2.5, 2.5]], dtype='float32')) # result3 = [[2.5, 2.5], [2.5, 2.5], [2.5, 2.5]] """ helper = LayerHelper('assign', **locals()) - check_type(input, 'input', (Variable, numpy.ndarray), 'assign') + check_type(input, 'input', (Variable, numpy.ndarray, list, tuple, float, + int, bool), 'assign') is_inplace = True if output is not None else False + if numpy.isscalar(input) and not isinstance(input, str): + input = numpy.array([input]) + elif isinstance(input, (list, tuple)): + input = numpy.array(input) + if isinstance(input, Variable): check_dtype( input.dtype, 'input', @@ -585,6 +593,14 @@ def assign(input, output=None): type='assign', inputs={'X': [input]}, outputs={'Out': [output]}) elif isinstance(input, numpy.ndarray): dtype = convert_np_dtype_to_dtype_(input.dtype) + if dtype == VarDesc.VarType.FP64: + # Setting FP64 numpy data is not supported in Paddle, so we + # use FP32 here + warnings.warn( + "paddle.assign doesn't support float64 input now due " + "to current platform protobuf data limitation, we convert " + "it to float32") + dtype = VarDesc.VarType.FP32 if dtype == VarDesc.VarType.BOOL: value_name = "bool_values" values = [bool(v) for v in input.flat] diff --git a/python/paddle/fluid/tests/unittests/dygraph_to_static/test_basic_api_transformation.py b/python/paddle/fluid/tests/unittests/dygraph_to_static/test_basic_api_transformation.py index 29b4f1b05f9..630b804f9a2 100644 --- a/python/paddle/fluid/tests/unittests/dygraph_to_static/test_basic_api_transformation.py +++ b/python/paddle/fluid/tests/unittests/dygraph_to_static/test_basic_api_transformation.py @@ -31,6 +31,10 @@ from paddle.fluid.dygraph.dygraph_to_static.utils import is_dygraph_api SEED = 2020 np.random.seed(SEED) +# TODO(zhhsplendid): This test is old so that use a static graph style +# mark it as TODO, to refactoring the code of this file. +paddle.enable_static() + def dyfunc_to_variable(x): res = fluid.dygraph.to_variable(x, name=None, zero_copy=None) @@ -54,11 +58,27 @@ def dyfunc_to_tensor(x): return res3 +def dyfunc_int_to_tensor(x): + res = paddle.to_tensor(3) + return res + + +def dyfunc_float_to_tensor(x): + res = paddle.to_tensor(2.0) + return res + + +def dyfunc_bool_to_tensor(x): + res = paddle.to_tensor(True) + return res + + class TestDygraphBasicApi_ToVariable(unittest.TestCase): def setUp(self): self.input = np.ones(5).astype("int32") self.test_funcs = [ - dyfunc_to_tensor, dyfunc_to_variable, dyfunc_to_variable_2, + dyfunc_to_tensor, dyfunc_bool_to_tensor, dyfunc_int_to_tensor, + dyfunc_float_to_tensor, dyfunc_to_variable, dyfunc_to_variable_2, dyfunc_to_variable_3 ] self.place = fluid.CUDAPlace(0) if fluid.is_compiled_with_cuda( diff --git a/python/paddle/fluid/tests/unittests/test_assign_op.py b/python/paddle/fluid/tests/unittests/test_assign_op.py index 82ddafb8f95..fe82b23b73b 100644 --- a/python/paddle/fluid/tests/unittests/test_assign_op.py +++ b/python/paddle/fluid/tests/unittests/test_assign_op.py @@ -94,10 +94,8 @@ class TestAssignOpError(unittest.TestCase): x3 = fluid.layers.data(name='x3', shape=[4], dtype="uint8") self.assertRaises(TypeError, fluid.layers.assign, x3) # When the type of input is numpy.ndarray, the dtype of input must be float32, int32. - x4 = np.array([[2.5, 2.5]], dtype='float64') + x4 = np.array([[2.5, 2.5]], dtype='uint8') self.assertRaises(TypeError, fluid.layers.assign, x4) - x5 = np.array([[2.5, 2.5]], dtype='uint8') - self.assertRaises(TypeError, fluid.layers.assign, x5) class TestAssignOApi(unittest.TestCase): @@ -157,6 +155,23 @@ class TestAssignOApi(unittest.TestCase): paddle.assign(array, result1) self.assertTrue(np.allclose(result1.numpy(), array)) + def test_assign_List(self): + paddle.disable_static() + l = [1, 2, 3] + result = paddle.assign(l) + self.assertTrue(np.allclose(result.numpy(), np.array(l))) + paddle.enable_static() + + def test_assign_BasicTypes(self): + paddle.disable_static() + result1 = paddle.assign(2) + result2 = paddle.assign(3.0) + result3 = paddle.assign(True) + self.assertTrue(np.allclose(result1.numpy(), np.array([2]))) + self.assertTrue(np.allclose(result2.numpy(), np.array([3.0]))) + self.assertTrue(np.allclose(result3.numpy(), np.array([1]))) + paddle.enable_static() + class TestAssignOpErrorApi(unittest.TestCase): def test_errors(self): @@ -169,10 +184,8 @@ class TestAssignOpErrorApi(unittest.TestCase): x3 = fluid.layers.data(name='x3', shape=[4], dtype="uint8") self.assertRaises(TypeError, paddle.assign, x3) # When the type of input is numpy.ndarray, the dtype of input must be float32, int32. - x4 = np.array([[2.5, 2.5]], dtype='float64') + x4 = np.array([[2.5, 2.5]], dtype='uint8') self.assertRaises(TypeError, paddle.assign, x4) - x5 = np.array([[2.5, 2.5]], dtype='uint8') - self.assertRaises(TypeError, paddle.assign, x5) if __name__ == '__main__': diff --git a/python/paddle/fluid/tests/unittests/xpu/test_assign_op_xpu.py b/python/paddle/fluid/tests/unittests/xpu/test_assign_op_xpu.py index 110e7bb3cbf..3eefa0bce88 100644 --- a/python/paddle/fluid/tests/unittests/xpu/test_assign_op_xpu.py +++ b/python/paddle/fluid/tests/unittests/xpu/test_assign_op_xpu.py @@ -85,11 +85,8 @@ class TestAssignOpError(unittest.TestCase): # When the type of input is Variable, the dtype of input must be float16, float32, float64, int32, int64, bool. x3 = fluid.layers.data(name='x3', shape=[4], dtype="uint8") self.assertRaises(TypeError, fluid.layers.assign, x3) - # When the type of input is numpy.ndarray, the dtype of input must be float32, int32. - x4 = np.array([[2.5, 2.5]], dtype='float64') + x4 = np.array([[2.5, 2.5]], dtype='uint8') self.assertRaises(TypeError, fluid.layers.assign, x4) - x5 = np.array([[2.5, 2.5]], dtype='uint8') - self.assertRaises(TypeError, fluid.layers.assign, x5) if __name__ == '__main__': diff --git a/python/paddle/tensor/creation.py b/python/paddle/tensor/creation.py index 69ee2962303..4cf10f8a69c 100644 --- a/python/paddle/tensor/creation.py +++ b/python/paddle/tensor/creation.py @@ -1036,8 +1036,8 @@ def assign(x, output=None): The OP copies the :attr:`x` to the :attr:`output`. Parameters: - x (Tensor|numpy.ndarray): A tensor or numpy ndarray, its data type supports - float16, float32, float64, int32 and int64. + x (Tensor|numpy.ndarray|list|tuple|scalar): A tensor, numpy ndarray, tuple, list or scalar, + its data type supports float16, float32, float64, int32, int64, and bool. output (Tensor, optional): A tensor. If :attr:`output` is None, a new tensor will be created as :attr:`output`. Default: None. @@ -1058,5 +1058,6 @@ def assign(x, output=None): result2 = paddle.assign(data) # result2 = [[2.5, 2.5], [2.5, 2.5], [2.5, 2.5]] result3 = paddle.assign(np.array([[2.5, 2.5], [2.5, 2.5], [2.5, 2.5]], dtype='float32')) # result3 = [[2.5, 2.5], [2.5, 2.5], [2.5, 2.5]] """ - check_type(x, 'x', (Variable, numpy.ndarray), 'assign') + check_type(x, 'x', (Variable, numpy.ndarray, list, tuple, float, int, bool), + 'assign') return tensor.assign(x, output) -- GitLab