Skip to content
This repository has been archived by the owner on Nov 17, 2023. It is now read-only.

Commit

Permalink
op empty_like, add nan_to_num to dispatch
Browse files Browse the repository at this point in the history
  • Loading branch information
Alicia1529 committed Nov 27, 2019
1 parent 8f10d55 commit c7bbfae
Show file tree
Hide file tree
Showing 7 changed files with 323 additions and 6 deletions.
72 changes: 71 additions & 1 deletion python/mxnet/ndarray/numpy/_op.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
from . import _internal as _npi
from ..ndarray import NDArray

__all__ = ['shape', 'zeros', 'ones', 'full', 'add', 'subtract', 'multiply', 'divide', 'mod', 'remainder', 'power',
__all__ = ['shape', 'zeros', 'ones', 'full', 'empty_like',
'add', 'subtract', 'multiply', 'divide', 'mod', 'remainder', 'power',
'arctan2', 'sin', 'cos', 'tan', 'sinh', 'cosh', 'tanh', 'log10', 'sqrt', 'cbrt', 'abs',
'absolute', 'exp', 'expm1', 'arcsin', 'arccos', 'arctan', 'sign', 'log', 'degrees', 'log2',
'log1p', 'rint', 'radians', 'reciprocal', 'square', 'negative', 'fix', 'ceil', 'floor',
Expand Down Expand Up @@ -200,6 +201,75 @@ def full(shape, fill_value, dtype=None, order='C', ctx=None, out=None):
# pylint: enable=too-many-arguments, redefined-outer-name


@set_module('mxnet.ndarray.numpy')
def empty_like(prototype, dtype=None, order='K', subok=True, shape=None): # pylint: disable=W0621
"""
Return a new array with the same shape and type as a given array.
Parameters
----------
prototype : ndarray
The shape and data-type of `prototype` define these same attributes
of the returned array.
dtype : data-type, optional
Overrides the data type of the result.
order : {'C', 'F', 'A', or 'K'}, optional
Overrides the memory layout of the result. 'C' means C-order,
'F' means F-order, 'A' means 'F' if ``prototype`` is Fortran
contiguous, 'C' otherwise. 'K' means match the layout of ``prototype``
as closely as possible.
subok : bool, optional.
If True, then the newly created array will use the sub-class
type of 'a', otherwise it will be a base-class array. Defaults
to True.
shape : int or sequence of ints, optional.
Overrides the shape of the result. If order='K' and the number of
dimensions is unchanged, will try to keep order, otherwise,
order='C' is implied.
(Not supported at this moment)
Returns
-------
out : ndarray
Array of uninitialized (arbitrary) data with the same
shape and type as `prototype`.
See Also
--------
ones_like : Return an array of ones with shape and type of input.
zeros_like : Return an array of zeros with shape and type of input.
full_like : Return a new array with shape of input filled with value.
empty : Return a new uninitialized array.
Notes
-----
This function does *not* initialize the returned array; to do that use
`zeros_like` or `ones_like` instead. It may be marginally faster than
the functions that do set the array values.
Examples
--------
>>> a = np.array([[1,2,3], [4,5,6]])
>>> np.empty_like(a)
array([[-5764607523034234880, -2305834244544065442, 4563075075], # uninitialized
[ 4567052944, -5764607523034234880, 844424930131968]])
>>> a = np.array([[1., 2., 3.],[4.,5.,6.]])
>>> np.empty_like(a)
array([[4.9e-324, 9.9e-324, 1.5e-323], # uninitialized
[2.0e-323, 2.5e-323, 3.0e-323]])
"""
dtype_list = {None:'None', _np.int8:'int8', _np.uint8:'uint8', _np.int32:'int32',
_np.int64:'int64', _np.float16:'float16', _np.float32:'float32',
_np.float64:'float64', _np.bool_:'bool'}
try:
dtype = dtype if isinstance(dtype, str) else dtype_list[dtype]
except:
raise NotImplementedError("Do not support this dtype at this moment")
return _npi.empty_like_fallback(prototype, dtype=dtype, order=order, subok=subok, shape=shape)


@set_module('mxnet.ndarray.numpy')
def arange(start, stop=None, step=1, dtype=None, ctx=None):
"""Return evenly spaced values within a given interval.
Expand Down
67 changes: 65 additions & 2 deletions python/mxnet/numpy/multiarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@
from ..ndarray.numpy import _internal as _npi
from ..ndarray.ndarray import _storage_type

__all__ = ['ndarray', 'empty', 'array', 'shape', 'zeros', 'ones', 'full', 'add', 'subtract', 'multiply', 'divide',
'mod', 'remainder', 'power', 'arctan2', 'sin', 'cos', 'tan', 'sinh', 'cosh', 'tanh', 'log10',
__all__ = ['ndarray', 'empty', 'array', 'shape', 'zeros', 'ones', 'full', 'empty_like',
'add', 'subtract', 'multiply', 'divide', 'mod', 'remainder', 'power',
'arctan2', 'sin', 'cos', 'tan', 'sinh', 'cosh', 'tanh', 'log10',
'sqrt', 'cbrt', 'abs', 'absolute', 'exp', 'expm1', 'arcsin', 'arccos', 'arctan', 'sign', 'log',
'degrees', 'log2', 'log1p', 'rint', 'radians', 'reciprocal', 'square', 'negative',
'fix', 'ceil', 'floor', 'trunc', 'logical_not', 'arcsinh', 'arccosh', 'arctanh', 'append',
Expand Down Expand Up @@ -2200,6 +2201,68 @@ def full(shape, fill_value, dtype=None, order='C', ctx=None, out=None):
# pylint: enable=too-many-arguments, redefined-outer-name


@set_module('mxnet.numpy')
def empty_like(prototype, dtype=None, order='K', subok=True, shape=None): # pylint: disable=W0621
"""
Return a new array with the same shape and type as a given array.
Parameters
----------
prototype : ndarray
The shape and data-type of `prototype` define these same attributes
of the returned array.
dtype : data-type, optional
Overrides the data type of the result.
order : {'C', 'F', 'A', or 'K'}, optional
Overrides the memory layout of the result. 'C' means C-order,
'F' means F-order, 'A' means 'F' if ``prototype`` is Fortran
contiguous, 'C' otherwise. 'K' means match the layout of ``prototype``
as closely as possible.
subok : bool, optional.
If True, then the newly created array will use the sub-class
type of 'a', otherwise it will be a base-class array. Defaults
to True.
shape : int or sequence of ints, optional.
Overrides the shape of the result. If order='K' and the number of
dimensions is unchanged, will try to keep order, otherwise,
order='C' is implied.
(Not supported at this moment)
Returns
-------
out : ndarray
Array of uninitialized (arbitrary) data with the same
shape and type as `prototype`.
See Also
--------
ones_like : Return an array of ones with shape and type of input.
zeros_like : Return an array of zeros with shape and type of input.
full_like : Return a new array with shape of input filled with value.
empty : Return a new uninitialized array.
Notes
-----
This function does *not* initialize the returned array; to do that use
`zeros_like` or `ones_like` instead. It may be marginally faster than
the functions that do set the array values.
Examples
--------
>>> a = np.array([[1,2,3], [4,5,6]])
>>> np.empty_like(a)
array([[-5764607523034234880, -2305834244544065442, 4563075075], # uninitialized
[ 4567052944, -5764607523034234880, 844424930131968]])
>>> a = np.array([[1., 2., 3.],[4.,5.,6.]])
>>> np.empty_like(a)
array([[4.9e-324, 9.9e-324, 1.5e-323], # uninitialized
[2.0e-323, 2.5e-323, 3.0e-323]])
"""
return _mx_nd_np.empty_like(prototype, dtype=dtype, order=order, subok=subok, shape=shape)


@set_module('mxnet.numpy')
def identity(n, dtype=None, ctx=None):
"""
Expand Down
2 changes: 2 additions & 0 deletions python/mxnet/numpy_dispatch_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ def _run_with_array_ufunc_proto(*args, **kwargs):
'diff',
'resize',
'where',
'empty_like',
'nan_to_num',
]


Expand Down
44 changes: 44 additions & 0 deletions python/mxnet/numpy_op_fallback.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"""Fallback-to-NumPy operator implementation."""

from __future__ import absolute_import
from distutils.version import StrictVersion
import functools
import ast
import numpy as np
Expand Down Expand Up @@ -49,6 +50,49 @@ def _register_helper(prop_cls):
return _register_helper


@use_np # enforce np shape and array semantics for all the methods in this class
class EmptyLike(operator.CustomOp):
"""Fallback to NumPy empty_like operator."""
def __init__(self, dtype, order, subok, shape):
super(EmptyLike, self).__init__()
self._dtype = dtype
self._order = order
self._subok = subok
self._shape = shape

def forward(self, is_train, req, in_data, out_data, aux):
np_version = np.version.version
if StrictVersion(np_version) >= StrictVersion('1.6.0'):
out = np.empty_like(in_data[0].asnumpy(), dtype=self._dtype, order=self._order,
subok=self._subok)
else:
out = np.empty_like(in_data[0].asnumpy())
self.assign(out_data[0], req[0], _mx_np.array(out, dtype=out.dtype, ctx=out_data[0].ctx))

def backward(self, req, out_grad, in_data, out_data, in_grad, aux):
raise NotImplementedError('Operator empty_like does not support gradient computation')


@register('empty_like_fallback')
class EmptyLikeProp(operator.CustomOpProp):
"""Fallback empty_like operator properties."""
def __init__(self, dtype, order, subok, shape):
super(EmptyLikeProp, self).__init__(need_top_grad=True)
self._dtype = None if dtype == 'None' else dtype
self._order = order
self._subok = ast.literal_eval(subok)
self._shape = ast.literal_eval(shape)

def list_arguments(self):
return ['prototype']

def infer_shape(self, in_shape):
return (in_shape[0],), (in_shape[0],), ()

def create_operator(self, ctx, in_shapes, in_dtypes):
return EmptyLike(self._dtype, self._order, self._subok, self._shape)


@use_np # enforce np shape and array semantics for all the methods in this class
class Resize(operator.CustomOp):
"""Fallback to NumPy resize operator."""
Expand Down
62 changes: 60 additions & 2 deletions python/mxnet/symbol/numpy/_symbol.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@
from .._internal import _set_np_symbol_class
from . import _internal as _npi

__all__ = ['zeros', 'ones', 'add', 'subtract', 'multiply', 'divide', 'mod', 'remainder', 'power', 'arctan2',
'sin', 'cos', 'tan', 'sinh', 'cosh', 'tanh', 'log10', 'sqrt', 'cbrt', 'abs', 'absolute', 'exp',
__all__ = ['zeros', 'ones', 'empty_like', 'add', 'subtract', 'multiply', 'divide', 'mod', 'remainder', 'power',
'arctan2', 'sin', 'cos', 'tan', 'sinh', 'cosh', 'tanh', 'log10', 'sqrt', 'cbrt', 'abs', 'absolute', 'exp',
'expm1', 'arcsin', 'arccos', 'arctan', 'sign', 'log', 'degrees', 'log2', 'log1p',
'rint', 'radians', 'reciprocal', 'square', 'negative', 'fix', 'ceil', 'floor',
'trunc', 'logical_not', 'arcsinh', 'arccosh', 'arctanh', 'tensordot', 'histogram', 'eye',
Expand Down Expand Up @@ -1343,6 +1343,64 @@ def eye(N, M=None, k=0, dtype=_np.float32, **kwargs):
return _npi.eye(N, M, k, ctx, dtype)


@set_module('mxnet.symbol.numpy')
def empty_like(prototype, dtype=None, order='K', subok=True, shape=None): # pylint: disable=W0621
"""
Return a new array with the same shape and type as a given array.
Parameters
----------
prototype : _Symbol
The shape and data-type of `prototype` define these same attributes
of the returned array.
dtype : data-type, optional
Overrides the data type of the result.
order : {'C', 'F', 'A', or 'K'}, optional
Overrides the memory layout of the result. 'C' means C-order,
'F' means F-order, 'A' means 'F' if ``prototype`` is Fortran
contiguous, 'C' otherwise. 'K' means match the layout of ``prototype``
as closely as possible.
subok : bool, optional.
If True, then the newly created array will use the sub-class
type of 'a', otherwise it will be a base-class array. Defaults
to True.
shape : int or sequence of ints, optional.
Overrides the shape of the result. If order='K' and the number of
dimensions is unchanged, will try to keep order, otherwise,
order='C' is implied.
(Not supported at this moment)
Returns
-------
out : _Symbol
Array of uninitialized (arbitrary) data with the same
shape and type as `prototype`.
See Also
--------
ones_like : Return an array of ones with shape and type of input.
zeros_like : Return an array of zeros with shape and type of input.
full_like : Return a new array with shape of input filled with value.
empty : Return a new uninitialized array.
Notes
-----
This function does *not* initialize the returned array; to do that use
`zeros_like` or `ones_like` instead. It may be marginally faster than
the functions that do set the array values.
"""
dtype_list = {None:'None', _np.int8:'int8', _np.uint8:'uint8', _np.int32:'int32',
_np.int64:'int64', _np.float16:'float16', _np.float32:'float32',
_np.float64:'float64', _np.bool_:'bool'}
try:
dtype = dtype if isinstance(dtype, str) else dtype_list[dtype]
except:
raise NotImplementedError("Do not support this dtype at this moment")
return _npi.empty_like_fallback(prototype, dtype=dtype, order=order, subok=subok, shape=shape)


@set_module('mxnet.symbol.numpy')
def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0, ctx=None): # pylint: disable=too-many-arguments
r"""
Expand Down
22 changes: 21 additions & 1 deletion tests/python/unittest/test_numpy_interoperability.py
Original file line number Diff line number Diff line change
Expand Up @@ -1299,6 +1299,24 @@ def _add_workload_resize():
OpArgMngr.add_workload('resize', np.zeros((10, 0)), (0, 10))
OpArgMngr.add_workload('resize', np.zeros((10, 0)), (0, 100))

def _add_workload_empty_like():
OpArgMngr.add_workload('empty_like', np.random.uniform(low=0, high=100, size=(1,3,4), dtype='float64'))
OpArgMngr.add_workload('empty_like', np.random.uniform(low=0, high=100, size=(9,3,1)), np.int32)
OpArgMngr.add_workload('empty_like', np.random.uniform(low=0, high=100, size=(9,3)), 'float32')
OpArgMngr.add_workload('empty_like', np.random.uniform(low=0, high=100, size=(9,3,1)), np.bool_, 'K', True)
OpArgMngr.add_workload('empty_like', np.random.uniform(low=0, high=100, size=(0,3)), np.float32)


def _add_workload_nan_to_num():
array1 = np.array([[-433, 0, 456, _np.inf], [-1, -_np.inf, 0, 1]])
array2 = np.array([_np.nan, _np.inf, -_np.inf, -574, 0, 23425, 24234,-5])
array3 = np.array(-_np.inf)
OpArgMngr.add_workload('nan_to_num', array1, True, 0, 100, -100)
OpArgMngr.add_workload('nan_to_num', array1, True, 0.00)
OpArgMngr.add_workload('nan_to_num', array2, True)
OpArgMngr.add_workload('nan_to_num', array2, True, -2000, 10000, -10000)
OpArgMngr.add_workload('nan_to_num', array3, True)


@use_np
def _prepare_workloads():
Expand Down Expand Up @@ -1420,6 +1438,8 @@ def _prepare_workloads():
_add_workload_shape()
_add_workload_diff()
_add_workload_resize()
_add_workload_empty_like()
_add_workload_nan_to_num()


_prepare_workloads()
Expand Down Expand Up @@ -1464,7 +1484,7 @@ def check_interoperability(op_list):
for name in op_list:
if name in _TVM_OPS and not is_op_runnable():
continue
if name in ['shares_memory', 'may_share_memory']: # skip list
if name in ['shares_memory', 'may_share_memory', 'empty_like']: # skip list
continue
print('Dispatch test:', name)
workloads = OpArgMngr.get_workloads(name)
Expand Down
Loading

0 comments on commit c7bbfae

Please sign in to comment.