未验证 提交 a6c50a6c 编写于 作者: T thunder95 提交者: GitHub

【PaddlePaddle Hackathon 3 No.15】为 Paddle 新增 count_nonzero (#44169)

* add count_nonzero api

* remove grad test
上级 05515662
...@@ -220,6 +220,7 @@ from .tensor.math import stanh # noqa: F401 ...@@ -220,6 +220,7 @@ from .tensor.math import stanh # noqa: F401
from .tensor.math import sum # noqa: F401 from .tensor.math import sum # noqa: F401
from .tensor.math import nansum # noqa: F401 from .tensor.math import nansum # noqa: F401
from .tensor.math import nanmean # noqa: F401 from .tensor.math import nanmean # noqa: F401
from .tensor.math import count_nonzero # noqa: F401
from .tensor.math import tanh # noqa: F401 from .tensor.math import tanh # noqa: F401
from .tensor.math import tanh_ # noqa: F401 from .tensor.math import tanh_ # noqa: F401
from .tensor.math import add_n # noqa: F401 from .tensor.math import add_n # noqa: F401
...@@ -560,6 +561,7 @@ __all__ = [ # noqa ...@@ -560,6 +561,7 @@ __all__ = [ # noqa
'sum', 'sum',
'nansum', 'nansum',
'nanmean', 'nanmean',
'count_nonzero',
'tile', 'tile',
'greater_equal', 'greater_equal',
'isfinite', 'isfinite',
......
# Copyright (c) 2022 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.
from __future__ import print_function
import unittest
import numpy as np
import paddle
import paddle.fluid as fluid
import paddle.fluid.core as core
from paddle.fluid import Program, program_guard
np.random.seed(10)
class TestCountNonzeroAPI(unittest.TestCase):
# test paddle.tensor.math.count_nonzero
def setUp(self):
self.x_shape = [2, 3, 4, 5]
self.x = np.random.uniform(-1, 1, self.x_shape).astype(np.float32)
self.place = paddle.CUDAPlace(0) if core.is_compiled_with_cuda() \
else paddle.CPUPlace()
def test_api_static(self):
paddle.enable_static()
with paddle.static.program_guard(paddle.static.Program()):
x = paddle.fluid.data('X', self.x_shape)
out1 = paddle.count_nonzero(x)
out2 = paddle.tensor.count_nonzero(x)
out3 = paddle.tensor.math.count_nonzero(x)
axis = np.arange(len(self.x_shape)).tolist()
out4 = paddle.count_nonzero(x, axis)
out5 = paddle.count_nonzero(x, tuple(axis))
exe = paddle.static.Executor(self.place)
res = exe.run(feed={'X': self.x},
fetch_list=[out1, out2, out3, out4, out5])
out_ref = np.count_nonzero(self.x)
for out in res:
self.assertEqual(np.allclose(out, out_ref), True)
def test_api_dygraph(self):
paddle.disable_static(self.place)
def test_case(x, axis=None, keepdim=False):
x_tensor = paddle.to_tensor(x)
out = paddle.count_nonzero(x_tensor, axis=axis, keepdim=keepdim)
if isinstance(axis, list):
axis = tuple(axis)
if len(axis) == 0:
axis = None
out_ref = np.count_nonzero(x, axis, keepdims=keepdim)
self.assertEqual(np.allclose(out.numpy(), out_ref), True)
test_case(self.x)
test_case(self.x, None)
test_case(self.x, -1)
test_case(self.x, keepdim=True)
test_case(self.x, 2, keepdim=True)
test_case(self.x, [0, 2])
test_case(self.x, (0, 2))
test_case(self.x, (0, 1, 3))
test_case(self.x, [0, 1, 2, 3])
paddle.enable_static()
def test_errors(self):
paddle.enable_static()
with paddle.static.program_guard(paddle.static.Program()):
x = paddle.fluid.data('X', [10, 12], 'int32')
self.assertRaises(ValueError, paddle.count_nonzero, x, axis=10)
if __name__ == "__main__":
unittest.main()
...@@ -168,6 +168,7 @@ from .math import stanh # noqa: F401 ...@@ -168,6 +168,7 @@ from .math import stanh # noqa: F401
from .math import sum # noqa: F401 from .math import sum # noqa: F401
from .math import nansum # noqa: F401 from .math import nansum # noqa: F401
from .math import nanmean # noqa: F401 from .math import nanmean # noqa: F401
from .math import count_nonzero # noqa: F401
from .math import tanh # noqa: F401 from .math import tanh # noqa: F401
from .math import tanh_ # noqa: F401 from .math import tanh_ # noqa: F401
from .math import add_n # noqa: F401 from .math import add_n # noqa: F401
...@@ -343,6 +344,7 @@ tensor_method_func = [ #noqa ...@@ -343,6 +344,7 @@ tensor_method_func = [ #noqa
'sum', 'sum',
'nansum', 'nansum',
'nanmean', 'nanmean',
'count_nonzero',
'tanh', 'tanh',
'tanh_', 'tanh_',
'add_n', 'add_n',
......
...@@ -1315,6 +1315,72 @@ def nanmean(x, axis=None, keepdim=False, name=None): ...@@ -1315,6 +1315,72 @@ def nanmean(x, axis=None, keepdim=False, name=None):
return paddle.divide(paddle.nansum(x, axis=axis, keepdim=keepdim, name=name), cnt.astype(x.dtype)) return paddle.divide(paddle.nansum(x, axis=axis, keepdim=keepdim, name=name), cnt.astype(x.dtype))
def count_nonzero(x, axis=None, keepdim=False, name=None):
r"""
Counts the number of non-zero values in the tensor x along the specified axis.
Args:
x (Tensor): An N-D Tensor, the data type is bool, float16, float32, float64, int32 or int64.
axis (int|list|tuple, optional): The dimensions along which the sum is performed. If
:attr:`None`, sum all elements of :attr:`x` and return a
Tensor with a single element, otherwise must be in the
range :math:`[-rank(x), rank(x))`. If :math:`axis[i] < 0`,
the dimension to reduce is :math:`rank + axis[i]`.
keepdim (bool, optional): Whether to reserve the reduced dimension in the
output Tensor. The result Tensor will have one fewer dimension
than the :attr:`x` unless :attr:`keepdim` is true, default
value is False.
name (str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`.
Returns:
Tensor: Results of count operation on the specified axis of input Tensor `x`, it's data type is `'int64'`.
Examples:
.. code-block:: python
:name: count_nonzero-example
import paddle
# x is a 2-D Tensor:
x = paddle.to_tensor([[0., 1.1, 1.2], [0., 0., 1.3], [0., 0., 0.]])
out1 = paddle.count_nonzero(x)
# [3]
out2 = paddle.count_nonzero(x, axis=0)
# [0, 1, 2]
out3 = paddle.count_nonzero(x, axis=0, keepdim=True)
# [[0, 1, 2]]
out4 = paddle.count_nonzero(x, axis=1)
# [2, 1, 0]
out5 = paddle.count_nonzero(x, axis=1, keepdim=True)
#[[2],
# [1],
# [0]]
# y is a 3-D Tensor:
y = paddle.to_tensor([[[0., 1.1, 1.2], [0., 0., 1.3], [0., 0., 0.]],
[[0., 2.5, 2.6], [0., 0., 2.4], [2.1, 2.2, 2.3]]])
out6 = paddle.count_nonzero(y, axis=[1, 2])
# [3, 6]
out7 = paddle.count_nonzero(y, axis=[0, 1])
# [1, 3, 5]
"""
if axis is not None:
if isinstance(axis, int):
axis = [axis]
dims = len(x.shape)
for i in range(len(axis)):
if not isinstance(axis[i], int) or not (axis[i] < dims and axis[i] >= -dims):
raise ValueError(
"Axis should be None, int, or a list, element should in range [-rank(x), rank(x))."
)
bool_tensor = paddle.cast(x, 'bool')
int_tensor = paddle.cast(bool_tensor, 'int64')
return paddle.sum(int_tensor, axis=axis, keepdim=keepdim, name=name)
@templatedoc(op_type="sum") @templatedoc(op_type="sum")
def add_n(inputs, name=None): def add_n(inputs, name=None):
""" """
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册