You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mxnet.apache.org by ha...@apache.org on 2020/04/02 04:05:38 UTC
[incubator-mxnet] branch master updated: [numpy] add op median
(#17084)
This is an automated email from the ASF dual-hosted git repository.
haoj pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-mxnet.git
The following commit(s) were added to refs/heads/master by this push:
new 08528c5 [numpy] add op median (#17084)
08528c5 is described below
commit 08528c5cb9449e634f55cb72ceb2b1910d176f80
Author: Yiyan66 <57...@users.noreply.github.com>
AuthorDate: Thu Apr 2 12:03:36 2020 +0800
[numpy] add op median (#17084)
* part
* wrapper
* sanity
---
3rdparty/mkldnn | 2 +-
python/mxnet/ndarray/numpy/_op.py | 51 +++++++++++++++++++++-
python/mxnet/numpy/multiarray.py | 51 +++++++++++++++++++++-
python/mxnet/numpy_dispatch_protocol.py | 1 +
python/mxnet/symbol/numpy/_symbol.py | 39 ++++++++++++++++-
.../python/unittest/test_numpy_interoperability.py | 9 ++++
tests/python/unittest/test_numpy_op.py | 40 +++++++++++++++++
7 files changed, 189 insertions(+), 4 deletions(-)
diff --git a/3rdparty/mkldnn b/3rdparty/mkldnn
index 8e96ef4..cb2cc7a 160000
--- a/3rdparty/mkldnn
+++ b/3rdparty/mkldnn
@@ -1 +1 @@
-Subproject commit 8e96ef49488c65e0738c552cec5c0563ab92c1af
+Subproject commit cb2cc7ac17ff4e2ef50805c7048d33256d82be4d
diff --git a/python/mxnet/ndarray/numpy/_op.py b/python/mxnet/ndarray/numpy/_op.py
index a1b6ff8..abd8147 100644
--- a/python/mxnet/ndarray/numpy/_op.py
+++ b/python/mxnet/ndarray/numpy/_op.py
@@ -36,7 +36,7 @@ __all__ = ['shape', 'zeros', 'zeros_like', 'ones', 'ones_like', 'full', 'full_li
'absolute', 'exp', 'expm1', 'arcsin', 'arccos', 'arctan', 'sign', 'log', 'degrees', 'log2', 'matmul',
'log1p', 'rint', 'radians', 'reciprocal', 'square', 'negative', 'fix', 'ceil', 'floor', 'histogram',
'trunc', 'logical_not', 'arcsinh', 'arccosh', 'arctanh', 'argsort', 'all', 'any', 'sort',
- 'tensordot', 'eye', 'linspace',
+ 'tensordot', 'eye', 'linspace', 'median',
'logspace', 'expand_dims', 'tile', 'arange', 'array_split', 'split', 'hsplit', 'vsplit', 'dsplit',
'concatenate', 'append', 'stack', 'vstack', 'row_stack', 'column_stack', 'hstack', 'dstack',
'average', 'mean', 'maximum', 'fmax', 'minimum', 'fmin', 'around', 'round', 'round_', 'flatnonzero',
@@ -6924,6 +6924,55 @@ def percentile(a, q, axis=None, out=None, overwrite_input=None, interpolation='l
@set_module('mxnet.ndarray.numpy')
+def median(a, axis=None, out=None, overwrite_input=None, keepdims=False):
+ r"""
+ Compute the median along the specified axis.
+ Returns the median of the array elements.
+ Parameters
+ ----------
+ a : array_like
+ Input array or object that can be converted to an array.
+ axis : {int, sequence of int, None}, optional
+ Axis or axes along which the medians are computed. The default
+ is to compute the median along a flattened version of the array.
+ A sequence of axes is supported since version 1.9.0.
+ out : ndarray, optional
+ Alternative output array in which to place the result. It must
+ have the same shape and buffer length as the expected output,
+ but the type (of the output) will be cast if necessary.
+ keepdims : bool, optional
+ If this is set to True, the axes which are reduced are left
+ in the result as dimensions with size one. With this option,
+ the result will broadcast correctly against the original `arr`.
+ Returns
+ -------
+ median : ndarray
+ A new array holding the result. If the input contains integers
+ or floats smaller than ``float32``, then the output data-type is
+ ``np.float32``. Otherwise, the data-type of the output is the
+ same as that of the input. If `out` is specified, that array is
+ returned instead.
+ See Also
+ --------
+ mean, percentile
+ Examples
+ --------
+ >>> a = np.array([[10, 7, 4], [3, 2, 1]])
+ >>> a
+ array([[10, 7, 4],
+ [ 3, 2, 1]])
+ >>> np.median(a)
+ 3.5
+ >>> np.median(a, axis=0)
+ array([6.5, 4.5, 2.5])
+ >>> np.median(a, axis=1)
+ array([7., 2.])
+ """
+ return quantile(a=a, q=0.5, axis=axis, out=out, overwrite_input=overwrite_input,
+ interpolation='midpoint', keepdims=keepdims)
+
+
+@set_module('mxnet.ndarray.numpy')
def quantile(a, q, axis=None, out=None, overwrite_input=None, interpolation='linear', keepdims=False): # pylint: disable=too-many-arguments
"""
Compute the q-th quantile of the data along the specified axis.
diff --git a/python/mxnet/numpy/multiarray.py b/python/mxnet/numpy/multiarray.py
index 281a6f7..aba1d7b 100644
--- a/python/mxnet/numpy/multiarray.py
+++ b/python/mxnet/numpy/multiarray.py
@@ -52,7 +52,7 @@ from .fallback import * # pylint: disable=wildcard-import,unused-wildcard-impor
from . import fallback
-__all__ = ['ndarray', 'empty', 'empty_like', 'array', 'shape',
+__all__ = ['ndarray', 'empty', 'empty_like', 'array', 'shape', 'median',
'zeros', 'zeros_like', 'ones', 'ones_like', 'full', 'full_like', 'all', 'any', 'broadcast_to',
'add', 'subtract', 'multiply', 'divide', 'mod', 'remainder', 'fmod', 'power', 'bitwise_not',
'delete',
@@ -8982,6 +8982,55 @@ def percentile(a, q, axis=None, out=None, overwrite_input=None, interpolation='l
@set_module('mxnet.numpy')
+def median(a, axis=None, out=None, overwrite_input=None, keepdims=False):
+ r"""
+ Compute the median along the specified axis.
+ Returns the median of the array elements.
+ Parameters
+ ----------
+ a : array_like
+ Input array or object that can be converted to an array.
+ axis : {int, sequence of int, None}, optional
+ Axis or axes along which the medians are computed. The default
+ is to compute the median along a flattened version of the array.
+ A sequence of axes is supported since version 1.9.0.
+ out : ndarray, optional
+ Alternative output array in which to place the result. It must
+ have the same shape and buffer length as the expected output,
+ but the type (of the output) will be cast if necessary.
+ keepdims : bool, optional
+ If this is set to True, the axes which are reduced are left
+ in the result as dimensions with size one. With this option,
+ the result will broadcast correctly against the original `arr`.
+ Returns
+ -------
+ median : ndarray
+ A new array holding the result. If the input contains integers
+ or floats smaller than ``float32``, then the output data-type is
+ ``np.float32``. Otherwise, the data-type of the output is the
+ same as that of the input. If `out` is specified, that array is
+ returned instead.
+ See Also
+ --------
+ mean, percentile
+ Examples
+ --------
+ >>> a = np.array([[10, 7, 4], [3, 2, 1]])
+ >>> a
+ array([[10, 7, 4],
+ [ 3, 2, 1]])
+ >>> np.median(a)
+ 3.5
+ >>> np.median(a, axis=0)
+ array([6.5, 4.5, 2.5])
+ >>> np.median(a, axis=1)
+ array([7., 2.])
+ """
+ return _mx_nd_np.median(a, axis=axis, overwrite_input=overwrite_input,
+ keepdims=keepdims, out=out)
+
+
+@set_module('mxnet.numpy')
def quantile(a, q, axis=None, out=None, overwrite_input=None, interpolation='linear', keepdims=False): # pylint: disable=too-many-arguments
"""
Compute the q-th quantile of the data along the specified axis.
diff --git a/python/mxnet/numpy_dispatch_protocol.py b/python/mxnet/numpy_dispatch_protocol.py
index 110f227..ab5893b 100644
--- a/python/mxnet/numpy_dispatch_protocol.py
+++ b/python/mxnet/numpy_dispatch_protocol.py
@@ -174,6 +174,7 @@ _NUMPY_ARRAY_FUNCTION_LIST = [
'shares_memory',
'may_share_memory',
'quantile',
+ 'median',
'percentile',
'diff',
'ediff1d',
diff --git a/python/mxnet/symbol/numpy/_symbol.py b/python/mxnet/symbol/numpy/_symbol.py
index a2a4cd9..451416b 100644
--- a/python/mxnet/symbol/numpy/_symbol.py
+++ b/python/mxnet/symbol/numpy/_symbol.py
@@ -39,7 +39,7 @@ __all__ = ['zeros', 'zeros_like', 'ones', 'ones_like', 'full', 'full_like', 'emp
'delete', 'add', 'broadcast_to', 'subtract', 'multiply', 'divide', 'mod', 'remainder', 'fmod',
'power', 'arctan2',
'sin', 'cos', 'tan', 'sinh', 'cosh', 'tanh', 'log10', 'sqrt', 'cbrt', 'abs', 'absolute', 'fabs', 'exp',
- 'expm1', 'arcsin', 'arccos', 'arctan', 'sign', 'log', 'degrees', 'log2', 'log1p', 'matmul',
+ 'expm1', 'arcsin', 'arccos', 'arctan', 'sign', 'log', 'degrees', 'log2', 'log1p', 'matmul', 'median',
'rint', 'radians', 'reciprocal', 'square', 'negative', 'fix', 'ceil', 'floor', 'histogram', 'insert',
'trunc', 'logical_not', 'arcsinh', 'arccosh', 'arctanh', 'argsort', 'sort', 'tensordot', 'eye', 'linspace',
'logspace', 'expand_dims', 'tile', 'arange', 'array_split', 'split', 'hsplit', 'vsplit', 'dsplit',
@@ -6164,6 +6164,43 @@ def percentile(a, q, axis=None, out=None, overwrite_input=None, interpolation='l
@set_module('mxnet.symbol.numpy')
+def median(a, axis=None, out=None, overwrite_input=None, keepdims=False):
+ r"""
+ Compute the median along the specified axis.
+ Returns the median of the array elements.
+ Parameters
+ ----------
+ a : _Symbol
+ Input array or object that can be converted to an array.
+ axis : {int, sequence of int, None}, optional
+ Axis or axes along which the medians are computed. The default
+ is to compute the median along a flattened version of the array.
+ A sequence of axes is supported since version 1.9.0.
+ out : _Symbol, optional
+ Alternative output array in which to place the result. It must
+ have the same shape and buffer length as the expected output,
+ but the type (of the output) will be cast if necessary.
+ keepdims : bool, optional
+ If this is set to True, the axes which are reduced are left
+ in the result as dimensions with size one. With this option,
+ the result will broadcast correctly against the original `arr`.
+ Returns
+ -------
+ median : _Symbol
+ A new array holding the result. If the input contains integers
+ or floats smaller than ``float32``, then the output data-type is
+ ``np.float32``. Otherwise, the data-type of the output is the
+ same as that of the input. If `out` is specified, that array is
+ returned instead.
+ See Also
+ --------
+ mean, percentile
+ """
+ return quantile(a=a, q=0.5, axis=axis, out=out, overwrite_input=overwrite_input,
+ interpolation='midpoint', keepdims=keepdims)
+
+
+@set_module('mxnet.symbol.numpy')
def quantile(a, q, axis=None, out=None, overwrite_input=None, interpolation='linear', keepdims=False): # pylint: disable=too-many-arguments
"""
Compute the q-th quantile of the data along the specified axis.
diff --git a/tests/python/unittest/test_numpy_interoperability.py b/tests/python/unittest/test_numpy_interoperability.py
index a4492a3..57ed9d8 100644
--- a/tests/python/unittest/test_numpy_interoperability.py
+++ b/tests/python/unittest/test_numpy_interoperability.py
@@ -178,6 +178,14 @@ def _add_workload_diagonal():
OpArgMngr.add_workload('diagonal', B, 0, 2, 1)
+def _add_workload_median(array_pool):
+ OpArgMngr.add_workload('median', array_pool['4x1'])
+ OpArgMngr.add_workload('median', array_pool['4x1'], axis=0, keepdims=True)
+ OpArgMngr.add_workload('median', np.array([[1, 2, 3], [4, 5, 6]]))
+ OpArgMngr.add_workload('median', np.array([[1, 2, 3], [4, 5, 6]]), axis=0)
+ OpArgMngr.add_workload('median', np.array([[1, 2, 3], [4, 5, 6]]), axis=1)
+
+
def _add_workload_quantile():
x1 = np.arange(8) * 0.5
x2 = np.arange(100.)
@@ -2915,6 +2923,7 @@ def _prepare_workloads():
_add_workload_diff()
_add_workload_ediff1d()
_add_workload_quantile()
+ _add_workload_median(array_pool)
_add_workload_percentile()
_add_workload_resize()
_add_workload_full_like(array_pool)
diff --git a/tests/python/unittest/test_numpy_op.py b/tests/python/unittest/test_numpy_op.py
index 3a8325c..25b2098 100644
--- a/tests/python/unittest/test_numpy_op.py
+++ b/tests/python/unittest/test_numpy_op.py
@@ -7388,6 +7388,46 @@ def test_np_share_memory():
assert not op(np.ones((5, 0), dtype=dt), np.ones((0, 3, 0), dtype=adt))
+def test_np_median():
+ class TestMedian(HybridBlock):
+ def __init__(self, axis=None, keepdims=False):
+ super(TestMedian, self).__init__()
+ self._axis = axis
+ self._keepdims = keepdims
+
+ def hybrid_forward(self, F, a):
+ return F.np.median(a, axis=self._axis, keepdims=self._keepdims)
+
+ flags = [True, False]
+ dtypes = ['float16', 'float32', 'float64']
+ qtypes = ['float32', 'float64']
+ tensor_shapes = [
+ ((2, 3), None),
+ ((2, 3, 4, 5), 3),
+ ((2, 3, 4), (0, 2)),
+ ((2, 3, 4), 1)
+ ]
+
+ for hybridize, keepdims, (a_shape, axis), dtype in \
+ itertools.product(flags, flags, tensor_shapes, dtypes):
+ atol = 3e-4 if dtype == 'float16' else 1e-4
+ rtol = 3e-2 if dtype == 'float16' else 1e-2
+ test_median = TestMedian(axis=axis, keepdims=keepdims)
+ if hybridize:
+ test_median.hybridize()
+ a = np.random.uniform(-1.0, 1.0, size=a_shape)
+ np_out = _np.median(a.asnumpy(), axis=axis, keepdims=keepdims)
+ mx_out = test_median(a)
+
+ assert mx_out.shape == np_out.shape
+ assert_almost_equal(mx_out.asnumpy(), np_out, atol=atol, rtol=rtol)
+
+ mx_out = np.median(a, axis=axis, keepdims=keepdims)
+ np_out = _np.median(a.asnumpy(), axis=axis, keepdims=keepdims)
+
+ assert_almost_equal(mx_out.asnumpy(), np_out, atol=atol, rtol=rtol)
+
+
@with_seed()
@use_np
def test_np_quantile():