From 52caf7870e6b5e6fdb3e0ea399f824d30218d799 Mon Sep 17 00:00:00 2001 From: liym27 <33742067+liym27@users.noreply.github.com> Date: Wed, 6 Jan 2021 10:45:03 +0800 Subject: [PATCH] [Cherry-pick 2.0] Migrate 4 APIs about array to paddle.tensor.* (#29565) (#30101) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 4 APIs: array_length, array_read, array_write, create_array,cherry-pick #29565 --- .../unittests/test_array_read_write_op.py | 60 +++++-- .../unittests/test_lod_array_length_op.py | 17 ++ python/paddle/tensor/__init__.py | 5 + python/paddle/tensor/array.py | 150 ++++++++++++++++++ 4 files changed, 221 insertions(+), 11 deletions(-) create mode 100644 python/paddle/tensor/array.py diff --git a/python/paddle/fluid/tests/unittests/test_array_read_write_op.py b/python/paddle/fluid/tests/unittests/test_array_read_write_op.py index add465d6c9b..b02cf67f4b2 100644 --- a/python/paddle/fluid/tests/unittests/test_array_read_write_op.py +++ b/python/paddle/fluid/tests/unittests/test_array_read_write_op.py @@ -15,6 +15,8 @@ from __future__ import print_function import unittest + +import paddle import paddle.fluid as fluid import paddle.fluid.core as core import paddle.fluid.layers as layers @@ -127,17 +129,53 @@ class TestArrayReadWrite(unittest.TestCase): class TestArrayReadWriteOpError(unittest.TestCase): - def test_errors(self): - with program_guard(Program(), Program()): - #for ci coverage - x1 = numpy.random.randn(2, 4).astype('int32') - x2 = fluid.layers.fill_constant(shape=[1], dtype='int32', value=1) - x3 = numpy.random.randn(2, 4).astype('int32') - - self.assertRaises( - TypeError, fluid.layers.array_read, array=x1, i=x2) - self.assertRaises( - TypeError, fluid.layers.array_write, array=x1, i=x2, out=x3) + def _test_errors(self, use_fluid_api=True): + if use_fluid_api: + with program_guard(Program(), Program()): + x1 = numpy.random.randn(2, 4).astype('int32') + x2 = fluid.layers.fill_constant( + shape=[1], dtype='int32', value=1) + x3 = numpy.random.randn(2, 4).astype('int32') + + self.assertRaises( + TypeError, fluid.layers.array_read, array=x1, i=x2) + self.assertRaises( + TypeError, fluid.layers.array_write, array=x1, i=x2, out=x3) + else: + with program_guard(Program(), Program()): + x1 = numpy.random.randn(2, 4).astype('int32') + x2 = paddle.ones(shape=[1], dtype='int32') + x3 = numpy.random.randn(2, 4).astype('int32') + + self.assertRaises( + TypeError, paddle.tensor.array_read, array=x1, i=x2) + self.assertRaises( + TypeError, + paddle.tensor.array_write, + array=x1, + i=x2, + out=x3) + + def test_fluid_api(self): + self._test_errors(use_fluid_api=True) + + def test_paddle_api(self): + self._test_errors(use_fluid_api=False) + + +class TestArrayReadWriteApi(unittest.TestCase): + def test_api(self): + paddle.disable_static() + arr = paddle.tensor.create_array(dtype="float32") + x = paddle.full(shape=[1, 3], fill_value=5, dtype="float32") + i = paddle.zeros(shape=[1], dtype="int32") + + arr = paddle.tensor.array_write(x, i, array=arr) + + item = paddle.tensor.array_read(arr, i) + + self.assertTrue(numpy.allclose(x.numpy(), item.numpy())) + paddle.enable_static() if __name__ == '__main__': diff --git a/python/paddle/fluid/tests/unittests/test_lod_array_length_op.py b/python/paddle/fluid/tests/unittests/test_lod_array_length_op.py index 363b474bfbb..353cdc5ab8b 100644 --- a/python/paddle/fluid/tests/unittests/test_lod_array_length_op.py +++ b/python/paddle/fluid/tests/unittests/test_lod_array_length_op.py @@ -15,6 +15,8 @@ from __future__ import print_function import unittest + +import paddle import paddle.fluid.layers as layers from paddle.fluid.executor import Executor import paddle.fluid.core as core @@ -44,5 +46,20 @@ class TestLoDArrayLengthOpError(unittest.TestCase): self.assertRaises(TypeError, fluid.layers.array_length, array=x1) +class TestArrayLengthApi(unittest.TestCase): + def test_api(self): + paddle.disable_static() + + arr = paddle.tensor.create_array(dtype='float32') + x = paddle.full(shape=[3, 3], fill_value=5, dtype="float32") + i = paddle.zeros(shape=[1], dtype="int32") + + arr = paddle.tensor.array_write(x, i, array=arr) + + arr_len = paddle.tensor.array_length(arr) + self.assertEqual(arr_len, 1) + paddle.enable_static() + + if __name__ == '__main__': unittest.main() diff --git a/python/paddle/tensor/__init__.py b/python/paddle/tensor/__init__.py index ecde9383450..ca330865863 100755 --- a/python/paddle/tensor/__init__.py +++ b/python/paddle/tensor/__init__.py @@ -202,3 +202,8 @@ from .stat import median #DEFINE_ALIAS # from .tensor import LoDTensor #DEFINE_ALIAS # from .tensor import LoDTensorArray #DEFINE_ALIAS from .to_string import set_printoptions #DEFINE_ALIAS + +from .array import array_length #DEFINE_ALIAS +from .array import array_read #DEFINE_ALIAS +from .array import array_write #DEFINE_ALIAS +from .array import create_array #DEFINE_ALIAS diff --git a/python/paddle/tensor/array.py b/python/paddle/tensor/array.py new file mode 100644 index 00000000000..ee28d47a9a9 --- /dev/null +++ b/python/paddle/tensor/array.py @@ -0,0 +1,150 @@ +# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Define functions about array. + +from ..fluid import layers + + +def array_length(array): + """ + This OP is used to get the length of the input array. + + Args: + array (list|Tensor): The input array that will be used to compute the length. In dynamic mode, ``array`` is a Python list. But in static mode, array is a Tensor whose VarType is LOD_TENSOR_ARRAY. + + Returns: + Tensor: 1-D Tensor with shape [1], which is the length of array. + + Examples: + .. code-block:: python + + import paddle + + arr = paddle.tensor.create_array(dtype='float32') + x = paddle.full(shape=[3, 3], fill_value=5, dtype="float32") + i = paddle.zeros(shape=[1], dtype="int32") + + arr = paddle.tensor.array_write(x, i, array=arr) + + arr_len = paddle.tensor.array_length(arr) + print(arr_len) # 1 + """ + return layers.array_length(array) + + +def array_read(array, i): + """ + This OP is used to read data at the specified position from the input array. + + Case: + + .. code-block:: text + + Input: + The shape of first three tensors are [1], and that of the last one is [1,2]: + array = ([0.6], [0.1], [0.3], [0.4, 0.2]) + And: + i = [3] + + Output: + output = [0.4, 0.2] + + Args: + array (list|Tensor): The input array. In dynamic mode, ``array`` is a Python list. But in static mode, array is a Tensor whose ``VarType`` is ``LOD_TENSOR_ARRAY``. + i (Tensor): 1-D Tensor, whose shape is [1] and dtype is int64. It represents the + specified read position of ``array``. + + Returns: + Tensor: A Tensor that is read at the specified position of ``array``. + + Examples: + .. code-block:: python + + import paddle + + arr = paddle.tensor.create_array(dtype="float32") + x = paddle.full(shape=[1, 3], fill_value=5, dtype="float32") + i = paddle.zeros(shape=[1], dtype="int32") + + arr = paddle.tensor.array_write(x, i, array=arr) + + item = paddle.tensor.array_read(arr, i) + print(item) # [[5., 5., 5.]] + """ + return layers.array_read(array, i) + + +def array_write(x, i, array=None): + """ + This OP writes the input ``x`` into the i-th position of the ``array`` returns the modified array. + If ``array`` is none, a new array will be created and returned. + + Args: + x (Tensor): The input data to be written into array. It's multi-dimensional + Tensor or LoDTensor. Data type: float32, float64, int32, int64 and bool. + i (Tensor): 1-D Tensor with shape [1], which represents the position into which + ``x`` is written. + array (list|Tensor, optional): The array into which ``x`` is written. The default value is None, + when a new array will be created and returned as a result. In dynamic mode, ``array`` is a Python list. + But in static mode, array is a Tensor whose ``VarType`` is ``LOD_TENSOR_ARRAY``. + + Returns: + list|Tensor: The input ``array`` after ``x`` is written into. + + Examples: + .. code-block:: python + + import paddle + + arr = paddle.tensor.create_array(dtype="float32") + x = paddle.full(shape=[1, 3], fill_value=5, dtype="float32") + i = paddle.zeros(shape=[1], dtype="int32") + + arr = paddle.tensor.array_write(x, i, array=arr) + + item = paddle.tensor.array_read(arr, i) + print(item) # [[5., 5., 5.]] + """ + return layers.array_write(x, i, array) + + +def create_array(dtype): + """ + This OP creates an array. It is used as the input of :ref:`api_paddle_tensor_array_array_read` and + :ref:`api_paddle_tensor_array_array_write`. + + Args: + dtype (str): The data type of the elements in the array. Support data type: float32, float64, int32, int64 and bool. + + Returns: + list|Tensor: An empty array. In dynamic mode, ``array`` is a Python list. But in static mode, array is a Tensor + whose ``VarType`` is ``LOD_TENSOR_ARRAY``. + + Examples: + .. code-block:: python + + import paddle + + arr = paddle.tensor.create_array(dtype="float32") + x = paddle.full(shape=[1, 3], fill_value=5, dtype="float32") + i = paddle.zeros(shape=[1], dtype="int32") + + arr = paddle.tensor.array_write(x, i, array=arr) + + item = paddle.tensor.array_read(arr, i) + print(item) # [[5., 5., 5.]] + + """ + return layers.create_array(dtype) -- GitLab