diff --git a/docs/api/python/ndarray.md b/docs/api/python/ndarray.md index 3f2cef24a73a..cc8a32dba9ae 100644 --- a/docs/api/python/ndarray.md +++ b/docs/api/python/ndarray.md @@ -110,6 +110,16 @@ We summarize the interface for each class in the following sections. NDArray.tostype ``` +### Array creation + +```eval_rst +.. autosummary:: + :nosignatures: + + NDArray.zeros_like + NDArray.ones_like +``` + ### Array change shape ```eval_rst @@ -118,7 +128,75 @@ We summarize the interface for each class in the following sections. NDArray.T NDArray.reshape + NDArray.flatten + NDArray.expand_dims + NDArray.split +``` + +### Array expand elements + +```eval_rst +.. autosummary:: + :nosignatures: + NDArray.broadcast_to + NDArray.broadcast_axes + NDArray.tile + NDArray.pad +``` + +### Array rearrange elements + +```eval_rst +.. autosummary:: + :nosignatures: + + NDArray.transpose + NDArray.swapaxes + NDArray.flip +``` + +### Array reduction + +```eval_rst +.. autosummary:: + :nosignatures: + + NDArray.sum + NDArray.nansum + NDArray.prod + NDArray.nanprod + NDArray.mean + NDArray.max + NDArray.min + NDArray.norm +``` + +### Array rounding + +```eval_rst +.. autosummary:: + :nosignatures: + + NDArray.round + NDArray.rint + NDArray.fix + NDArray.floor + NDArray.ceil + NDArray.trunc +``` + +### Array sorting and searching + +```eval_rst +.. autosummary:: + :nosignatures: + + NDArray.sort + NDArray.argsort + NDArray.topk + NDArray.argmax + NDArray.argmin ``` ### Arithmetic operations @@ -174,6 +252,11 @@ We summarize the interface for each class in the following sections. NDArray.__getitem__ NDArray.__setitem__ + NDArray.slice + NDArray.slice_axis + NDArray.take + NDArray.one_hot + NDArray.pick ``` ### Lazy evaluation @@ -185,6 +268,16 @@ We summarize the interface for each class in the following sections. NDArray.wait_to_read ``` +### Miscellaneous + +```eval_rst +.. autosummary:: + :nosignatures: + + NDArray.clip + NDArray.sign +``` + ## The `sparse.RowSparseNDArray` Class ```eval_rst @@ -223,7 +316,9 @@ We summarize the interface for each class in the following sections. array empty zeros + zeros_like ones + ones_like full arange load @@ -290,6 +385,7 @@ We summarize the interface for each class in the following sections. batch_take one_hot pick + where ``` ## Mathematical functions @@ -323,6 +419,7 @@ We summarize the interface for each class in the following sections. arcsin arccos arctan + broadcast_hypot degrees radians ``` @@ -424,6 +521,13 @@ We summarize the interface for each class in the following sections. random_poisson random_negative_binomial random_generalized_negative_binomial + sample_uniform + sample_normal + sample_gamma + sample_exponential + sample_poisson + sample_negative_binomial + sample_generalized_negative_binomial mxnet.random.seed ``` @@ -440,6 +544,21 @@ We summarize the interface for each class in the following sections. argmin ``` +### Linear Algebra + +```eval_rst +.. autosummary:: + :nosignatures: + + linalg_gemm + linalg_gemm2 + linalg_potrf + linalg_potri + linalg_trmm + linalg_trsm + linalg_sumlogdiag +``` + ### Miscellaneous ```eval_rst diff --git a/docs/api/python/symbol.md b/docs/api/python/symbol.md index dd455eee587a..55e459798f61 100644 --- a/docs/api/python/symbol.md +++ b/docs/api/python/symbol.md @@ -105,8 +105,95 @@ Composite multiple symbols into a new one by an operator. Symbol.__ne__ ``` -### Query information +### Symbol creation + +```eval_rst +.. autosummary:: + :nosignatures: + + Symbol.zeros_like + Symbol.ones_like +``` + +### Changing shape and type + +```eval_rst +.. autosummary:: + :nosignatures: + + Symbol.astype + Symbol.reshape + Symbol.flatten + Symbol.expand_dims +``` + +### Expanding elements + +```eval_rst +.. autosummary:: + :nosignatures: + + Symbol.broadcast_to + Symbol.broadcast_axes + Symbol.tile + Symbol.pad +``` + +### Rearranging elements + +```eval_rst +.. autosummary:: + :nosignatures: + + Symbol.transpose + Symbol.swapaxes + Symbol.flip +``` + +### Reduce functions + +```eval_rst +.. autosummary:: + :nosignatures: + Symbol.sum + Symbol.nansum + Symbol.prod + Symbol.nanprod + Symbol.mean + Symbol.max + Symbol.min + Symbol.norm +``` + +### Rounding + +```eval_rst +.. autosummary:: + :nosignatures: + + Symbol.round + Symbol.rint + Symbol.fix + Symbol.floor + Symbol.ceil + Symbol.trunc +``` + +### Sorting and searching + +```eval_rst +.. autosummary:: + :nosignatures: + + Symbol.sort + Symbol.argsort + Symbol.topk + Symbol.argmax + Symbol.argmin +``` + +### Query information ```eval_rst .. autosummary:: @@ -121,6 +208,19 @@ Composite multiple symbols into a new one by an operator. Symbol.attr_dict ``` +### Indexing + +```eval_rst +.. autosummary:: + :nosignatures: + + Symbol.slice + Symbol.slice_axis + Symbol.take + Symbol.one_hot + Symbol.pick +``` + ### Get internal and output symbol ```eval_rst @@ -166,6 +266,16 @@ Composite multiple symbols into a new one by an operator. Symbol.debug_str ``` +### Miscellaneous + +```eval_rst +.. autosummary:: + :nosignatures: + + Symbol.clip + Symbol.sign +``` + ## Symbol creation routines ```eval_rst @@ -174,7 +284,9 @@ Composite multiple symbols into a new one by an operator. var zeros + zeros_like ones + ones_like arange ``` @@ -237,6 +349,8 @@ Composite multiple symbols into a new one by an operator. take batch_take one_hot + pick + where ``` ## Mathematical functions @@ -516,8 +630,16 @@ The `contrib.symbol` module contains many useful experimental APIs for new featu ```eval_rst + +.. autoclass:: mxnet.symbol.Symbol + :members: + :special-members: + .. automodule:: mxnet.symbol :members: + :imported-members: + :special-members: + :exclude-members: Symbol .. automodule:: mxnet.contrib.symbol :members: diff --git a/include/mxnet/c_api.h b/include/mxnet/c_api.h index a43f73fe45ab..bba61909350d 100644 --- a/include/mxnet/c_api.h +++ b/include/mxnet/c_api.h @@ -691,7 +691,7 @@ MXNET_DLL int MXImperativeInvokeEx(AtomicSymbolCreator creator, MXNET_DLL int MXAutogradSetIsRecording(int is_recording, int* prev); /*! * \brief set whether to record operator for autograd - * \param is_train 1 when training, 0 when testing + * \param is_training 1 when training, 0 when testing * \param prev returns the previous status before this set. * \return 0 when success, -1 when failure happens */ diff --git a/python/mxnet/ndarray/ndarray.py b/python/mxnet/ndarray/ndarray.py index 7322325722d6..a85ccb5b6076 100644 --- a/python/mxnet/ndarray/ndarray.py +++ b/python/mxnet/ndarray/ndarray.py @@ -16,7 +16,7 @@ # under the License. # coding: utf-8 -# pylint: disable= too-many-lines, redefined-builtin, protected-access +# pylint: disable=too-many-lines, protected-access # pylint: disable=import-error, no-name-in-module, undefined-variable """NDArray API of MXNet.""" from __future__ import absolute_import @@ -38,10 +38,15 @@ from ..context import Context from . import _internal from .op import NDArrayBase, _STORAGE_TYPE_ID_TO_STR +from . import cast_storage from . import broadcast_add, broadcast_mul, transpose, broadcast_not_equal, broadcast_power -from . import broadcast_sub, broadcast_div, broadcast_to, broadcast_equal, cast_storage +from . import broadcast_sub, broadcast_div, broadcast_to, broadcast_axes, broadcast_equal from . import broadcast_greater, broadcast_greater_equal, broadcast_lesser, broadcast_lesser_equal -from . import zeros_like, slice, broadcast_minimum, broadcast_maximum, broadcast_mod +from . import zeros_like, ones_like, broadcast_minimum, broadcast_maximum, broadcast_mod +from . import flatten, norm, rint, fix, floor, ceil, split, slice_axis, one_hot, pick, take +from . import trunc, expand_dims, flip, tile, repeat, pad, clip, sign +from . import nansum, prod, nanprod, mean, sort, topk, argsort, argmax, argmin +from . import sum, round, max, min, slice, abs # pylint: disable=redefined-builtin __all__ = ["NDArray", "concatenate", "_DTYPE_NP_TO_MX", "_DTYPE_MX_TO_NP", "_GRAD_REQ_MAP", "ones", "add", "arange", "divide", "equal", "full", "greater", "greater_equal", @@ -673,6 +678,318 @@ def reshape(self, shape): ctypes.byref(handle))) return NDArray(handle=handle, writable=self.writable) + def zeros_like(self, *args, **kwargs): + """Convenience fluent method for :py:func:`zeros_like`. + + The arguments are the same as for :py:func:`zeros_like`, with + this array as data. + """ + return zeros_like(self, *args, **kwargs) + + def ones_like(self, *args, **kwargs): + """Convenience fluent method for :py:func:`ones_like`. + + The arguments are the same as for :py:func:`ones_like`, with + this array as data. + """ + return ones_like(self, *args, **kwargs) + + def broadcast_axes(self, *args, **kwargs): + """Convenience fluent method for :py:func:`broadcast_axes`. + + The arguments are the same as for :py:func:`broadcast_axes`, with + this array as data. + """ + return broadcast_axes(self, *args, **kwargs) + + def repeat(self, *args, **kwargs): + """Convenience fluent method for :py:func:`repeat`. + + The arguments are the same as for :py:func:`repeat`, with + this array as data. + """ + return repeat(self, *args, **kwargs) + + def pad(self, *args, **kwargs): + """Convenience fluent method for :py:func:`pad`. + + The arguments are the same as for :py:func:`pad`, with + this array as data. + """ + return pad(self, *args, **kwargs) + + def swapaxes(self, *args, **kwargs): + """Convenience fluent method for :py:func:`swapaxes`. + + The arguments are the same as for :py:func:`swapaxes`, with + this array as data. + """ + return swapaxes(self, *args, **kwargs) + + def split(self, *args, **kwargs): + """Convenience fluent method for :py:func:`split`. + + The arguments are the same as for :py:func:`split`, with + this array as data. + """ + return split(self, *args, **kwargs) + + def slice(self, *args, **kwargs): + """Convenience fluent method for :py:func:`slice`. + + The arguments are the same as for :py:func:`slice`, with + this array as data. + """ + return slice(self, *args, **kwargs) + + def slice_axis(self, *args, **kwargs): + """Convenience fluent method for :py:func:`slice_axis`. + + The arguments are the same as for :py:func:`slice_axis`, with + this array as data. + """ + return slice_axis(self, *args, **kwargs) + + def take(self, *args, **kwargs): + """Convenience fluent method for :py:func:`take`. + + The arguments are the same as for :py:func:`take`, with + this array as data. + """ + return take(self, *args, **kwargs) + + def one_hot(self, *args, **kwargs): + """Convenience fluent method for :py:func:`one_hot`. + + The arguments are the same as for :py:func:`one_hot`, with + this array as data. + """ + return one_hot(self, *args, **kwargs) + + def pick(self, *args, **kwargs): + """Convenience fluent method for :py:func:`pick`. + + The arguments are the same as for :py:func:`pick`, with + this array as data. + """ + return pick(self, *args, **kwargs) + + def sort(self, *args, **kwargs): + """Convenience fluent method for :py:func:`sort`. + + The arguments are the same as for :py:func:`sort`, with + this array as data. + """ + return sort(self, *args, **kwargs) + + def topk(self, *args, **kwargs): + """Convenience fluent method for :py:func:`topk`. + + The arguments are the same as for :py:func:`topk`, with + this array as data. + """ + return topk(self, *args, **kwargs) + + def argsort(self, *args, **kwargs): + """Convenience fluent method for :py:func:`argsort`. + + The arguments are the same as for :py:func:`argsort`, with + this array as data. + """ + return argsort(self, *args, **kwargs) + + def argmax(self, *args, **kwargs): + """Convenience fluent method for :py:func:`argmax`. + + The arguments are the same as for :py:func:`argmax`, with + this array as data. + """ + return argmax(self, *args, **kwargs) + + def argmin(self, *args, **kwargs): + """Convenience fluent method for :py:func:`argmin`. + + The arguments are the same as for :py:func:`argmin`, with + this array as data. + """ + return argmin(self, *args, **kwargs) + + def clip(self, *args, **kwargs): + """Convenience fluent method for :py:func:`clip`. + + The arguments are the same as for :py:func:`clip`, with + this array as data. + """ + return clip(self, *args, **kwargs) + + def abs(self, *args, **kwargs): + """Convenience fluent method for :py:func:`abs`. + + The arguments are the same as for :py:func:`abs`, with + this array as data. + """ + return abs(self, *args, **kwargs) + + def sign(self, *args, **kwargs): + """Convenience fluent method for :py:func:`sign`. + + The arguments are the same as for :py:func:`sign`, with + this array as data. + """ + return sign(self, *args, **kwargs) + + def flatten(self, *args, **kwargs): + """Convenience fluent method for :py:func:`flatten`. + + The arguments are the same as for :py:func:`flatten`, with + this array as data. + """ + return flatten(self, *args, **kwargs) + + def expand_dims(self, *args, **kwargs): + """Convenience fluent method for :py:func:`expand_dims`. + + The arguments are the same as for :py:func:`expand_dims`, with + this array as data. + """ + return expand_dims(self, *args, **kwargs) + + def tile(self, *args, **kwargs): + """Convenience fluent method for :py:func:`tile`. + + The arguments are the same as for :py:func:`tile`, with + this array as data. + """ + return tile(self, *args, **kwargs) + + def transpose(self, *args, **kwargs): + """Convenience fluent method for :py:func:`transpose`. + + The arguments are the same as for :py:func:`transpose`, with + this array as data. + """ + return transpose(self, *args, **kwargs) + + def flip(self, *args, **kwargs): + """Convenience fluent method for :py:func:`flip`. + + The arguments are the same as for :py:func:`flip`, with + this array as data. + """ + return flip(self, *args, **kwargs) + + def sum(self, *args, **kwargs): + """Convenience fluent method for :py:func:`sum`. + + The arguments are the same as for :py:func:`sum`, with + this array as data. + """ + return sum(self, *args, **kwargs) + + def nansum(self, *args, **kwargs): + """Convenience fluent method for :py:func:`nansum`. + + The arguments are the same as for :py:func:`nansum`, with + this array as data. + """ + return nansum(self, *args, **kwargs) + + def prod(self, *args, **kwargs): + """Convenience fluent method for :py:func:`prod`. + + The arguments are the same as for :py:func:`prod`, with + this array as data. + """ + return prod(self, *args, **kwargs) + + def nanprod(self, *args, **kwargs): + """Convenience fluent method for :py:func:`nanprod`. + + The arguments are the same as for :py:func:`nanprod`, with + this array as data. + """ + return nanprod(self, *args, **kwargs) + + def mean(self, *args, **kwargs): + """Convenience fluent method for :py:func:`mean`. + + The arguments are the same as for :py:func:`mean`, with + this array as data. + """ + return mean(self, *args, **kwargs) + + def max(self, *args, **kwargs): + """Convenience fluent method for :py:func:`max`. + + The arguments are the same as for :py:func:`max`, with + this array as data. + """ + return max(self, *args, **kwargs) + + def min(self, *args, **kwargs): + """Convenience fluent method for :py:func:`min`. + + The arguments are the same as for :py:func:`min`, with + this array as data. + """ + return min(self, *args, **kwargs) + + def norm(self, *args, **kwargs): + """Convenience fluent method for :py:func:`norm`. + + The arguments are the same as for :py:func:`norm`, with + this array as data. + """ + return norm(self, *args, **kwargs) + + def round(self, *args, **kwargs): + """Convenience fluent method for :py:func:`round`. + + The arguments are the same as for :py:func:`round`, with + this array as data. + """ + return round(self, *args, **kwargs) + + def rint(self, *args, **kwargs): + """Convenience fluent method for :py:func:`rint`. + + The arguments are the same as for :py:func:`rint`, with + this array as data. + """ + return rint(self, *args, **kwargs) + + def fix(self, *args, **kwargs): + """Convenience fluent method for :py:func:`fix`. + + The arguments are the same as for :py:func:`fix`, with + this array as data. + """ + return fix(self, *args, **kwargs) + + def floor(self, *args, **kwargs): + """Convenience fluent method for :py:func:`floor`. + + The arguments are the same as for :py:func:`floor`, with + this array as data. + """ + return floor(self, *args, **kwargs) + + def ceil(self, *args, **kwargs): + """Convenience fluent method for :py:func:`ceil`. + + The arguments are the same as for :py:func:`ceil`, with + this array as data. + """ + return ceil(self, *args, **kwargs) + + def trunc(self, *args, **kwargs): + """Convenience fluent method for :py:func:`trunc`. + + The arguments are the same as for :py:func:`trunc`, with + this array as data. + """ + return trunc(self, *args, **kwargs) + # pylint: disable= undefined-variable def broadcast_to(self, shape): """Broadcasts the input array to a new shape. @@ -1281,7 +1598,7 @@ def moveaxis(tensor, source, destination): return transpose(tensor, axes) -# pylint: disable= no-member, protected-access, too-many-arguments +# pylint: disable= no-member, protected-access, too-many-arguments, redefined-outer-name def arange(start, stop=None, step=1.0, repeat=1, ctx=None, dtype=mx_real_t): """Returns evenly spaced values within a given interval. @@ -2330,6 +2647,7 @@ def concatenate(arrays, axis=0, always_copy=True): return ret +# pylint: disable=redefined-outer-name def imdecode(str_img, clip_rect=(0, 0, 0, 0), out=None, index=0, channels=3, mean=None): """DEPRECATED, use mx.img instead diff --git a/python/mxnet/symbol/symbol.py b/python/mxnet/symbol/symbol.py index aa8ca0b8dd53..0038840540c2 100644 --- a/python/mxnet/symbol/symbol.py +++ b/python/mxnet/symbol/symbol.py @@ -40,7 +40,11 @@ from ..ndarray.ndarray import _STORAGE_TYPE_STR_TO_ID from ..ndarray import _ndarray_cls from ..executor import Executor -from . import _internal, reshape +from . import _internal, reshape, transpose, zeros_like, ones_like, broadcast_axes, broadcast_to +from . import flatten, norm, rint, fix, floor, ceil, split, slice_axis, one_hot, pick, take +from . import trunc, expand_dims, flip, tile, repeat, pad, clip, sign +from . import nansum, prod, nanprod, mean, sort, topk, argsort, argmax, argmin +from . import sum, round, max, min, slice, abs # pylint: disable=redefined-builtin from .op import SymbolBase, _set_symbol_class, AttrScope, _Null # pylint: disable=unused-import @@ -64,8 +68,8 @@ def __iter__(self): One can loop through the returned object list to get outputs. - Example usage: - ---------- + Example + ------- >>> a = mx.sym.Variable('a') >>> b = mx.sym.Variable('b') >>> c = a+b @@ -120,8 +124,8 @@ def __rsub__(self, other): Only `NDArray` is supported for now. - Example usage: - ---------- + Example + ------- >>> x = mx.nd.ones((2,3))*3 >>> y = mx.nd.ones((2,3)) >>> x.__rsub__(y).asnumpy() @@ -168,8 +172,8 @@ def __rdiv__(self, other): Only `NDArray` is supported for now. - Example usage: - ---------- + Example + ------- >>> x = mx.nd.ones((2,3))*3 >>> y = mx.nd.ones((2,3)) >>> x.__rdiv__(y).asnumpy() @@ -198,8 +202,8 @@ def __rmod__(self, other): Only `NDArray` is supported for now. - Example usage: - ---------- + Example + ------- >>> x = mx.nd.ones((2,3))*3 >>> y = mx.nd.ones((2,3)) >>> x.__rmod__(y).asnumpy() @@ -243,8 +247,8 @@ def __neg__(self): Numerical negative, element-wise. - Example usage: - ---------- + Example + ------- >>> a = mx.sym.Variable('a') >>> a @@ -270,8 +274,8 @@ def __deepcopy__(self, _): Any changes made to the deep copy do not reflect in the original object. - Example usage: - ---------- + Example + ------- >>> import copy >>> data = mx.sym.Variable('data') >>> data_1 = copy.deepcopy(data) @@ -383,8 +387,8 @@ def __call__(self, *args, **kwargs): This function internally calls `_compose` to compose the symbol and returns the composed symbol. - Example usage: - ---------- + Example + ------- >>> data = mx.symbol.Variable('data') >>> net1 = mx.symbol.FullyConnected(data=data, name='fc1', num_hidden=10) >>> net2 = mx.symbol.FullyConnected(name='fc3', num_hidden=10) @@ -418,8 +422,8 @@ def _compose(self, *args, **kwargs): This function mutates the current symbol. - Example usage: - ---------- + Example + ------- >>> data = mx.symbol.Variable('data') >>> net1 = mx.symbol.FullyConnected(data=data, name='fc1', num_hidden=10) >>> net2 = mx.symbol.FullyConnected(name='fc3', num_hidden=10) @@ -471,8 +475,8 @@ def __getitem__(self, index): Returns a sliced view of the input symbol. - Example usage: - ---------- + Example + ------- >>> a = mx.sym.var('a') >>> a.__getitem__(0) @@ -536,8 +540,8 @@ def attr(self, key): This function only works for non-grouped symbols. - Example usage: - ---------- + Example + ------- >>> data = mx.sym.Variable('data', attr={'mood': 'angry'}) >>> data.attr('mood') 'angry' @@ -564,8 +568,8 @@ def attr(self, key): def list_attr(self, recursive=False): """Gets all attributes from the symbol. - Example usage: - ---------- + Example + ------- >>> data = mx.sym.Variable('data', attr={'mood': 'angry'}) >>> data.list_attr() {'mood': 'angry'} @@ -587,8 +591,8 @@ def list_attr(self, recursive=False): def attr_dict(self): """Recursively gets all attributes from the symbol and its children. - Example usage: - ---------- + Example + ------- >>> a = mx.sym.Variable('a', attr={'a1':'a2'}) >>> b = mx.sym.Variable('b', attr={'b1':'b2'}) >>> c = a+b @@ -638,8 +642,8 @@ def get_internals(self): Consider the following code: - Example usage: - ---------- + Example + ------- >>> a = mx.sym.var('a') >>> b = mx.sym.var('b') >>> c = a + b @@ -664,8 +668,8 @@ def get_children(self): """Gets a new grouped symbol whose output contains inputs to output nodes of the original symbol. - Example usage: - ---------- + Example + ------- >>> x = mx.sym.Variable('x') >>> y = mx.sym.Variable('y') >>> z = mx.sym.Variable('z') @@ -695,8 +699,8 @@ def get_children(self): def list_arguments(self): """Lists all the arguments in the symbol. - Example usage: - ---------- + Example + ------- >>> a = mx.sym.var('a') >>> b = mx.sym.var('b') >>> c = a + b @@ -717,8 +721,8 @@ def list_arguments(self): def list_outputs(self): """Lists all the outputs in the symbol. - Example usage: - ---------- + Example + ------- >>> a = mx.sym.var('a') >>> b = mx.sym.var('b') >>> c = a + b @@ -742,8 +746,8 @@ def list_outputs(self): def list_auxiliary_states(self): """Lists all the auxiliary states in the symbol. - Example usage: - ---------- + Example + ------- >>> a = mx.sym.var('a') >>> b = mx.sym.var('b') >>> c = a + b @@ -811,8 +815,8 @@ def infer_type(self, *args, **kwargs): Inconsistencies in the known types will cause an error to be raised. - Example usage: - ---------- + Example + ------- >>> a = mx.sym.var('a') >>> b = mx.sym.var('b') >>> c = a + b @@ -906,8 +910,8 @@ def infer_shape(self, *args, **kwargs): or keyword argument way as input. It returns a tuple of `None` values if there is not enough information to deduce the missing shapes. - Example usage: - ---------- + Example + ------- >>> a = mx.sym.var('a') >>> b = mx.sym.var('b') >>> c = a + b @@ -989,8 +993,8 @@ def infer_shape_partial(self, *args, **kwargs): In the following example, information about fc2 is not available. So, `infer_shape` will return a tuple of `None` values but `infer_shape_partial` will return partial values. - Example usage: - ---------- + Example + ------- >>> data = mx.sym.Variable('data') >>> prev = mx.sym.Variable('prev') >>> fc1 = mx.sym.FullyConnected(data=data, name='fc1', num_hidden=128) @@ -1253,8 +1257,8 @@ def simple_bind(self, ctx, grad_req='write', type_dict=None, stype_dict=None, Before binding the executor, the function allocates arguments and auxiliary states that were not explicitly specified. Allows specifying data types. - Example usage: - ---------- + Example + ------- >>> x = mx.sym.Variable('x') >>> y = mx.sym.FullyConnected(x, num_hidden=4) >>> exe = y.simple_bind(mx.cpu(), x=(5,4), grad_req='null') @@ -1515,8 +1519,8 @@ def bind(self, ctx, args, args_grad=None, grad_req='write', This function returns an executor which provides method `forward()` method for evaluation and a `outputs()` method to get all the results. - Example usage: - ---------- + Example + ------- >>> a = mx.sym.Variable('a') >>> b = mx.sym.Variable('b') >>> c = a + b @@ -1702,8 +1706,8 @@ def eval(self, ctx=None, **kwargs): In that case, you should call `bind` once and then repeatedly call forward. This function allows simpler syntax for less cumbersome introspection. - Example usage: - ---------- + Example + ------- >>> a = mx.sym.Variable('a') >>> b = mx.sym.Variable('b') >>> c = a + b @@ -1732,24 +1736,341 @@ def eval(self, ctx=None, **kwargs): ctx = Context.default_ctx return self.bind(ctx, kwargs).forward() - def reshape(self, shape): - """Shorthand for mxnet.sym.reshape. + def reshape(self, *args, **kwargs): + """Convenience fluent method for :py:func:`reshape`. - Parameters - ---------- - shape : tuple of int - The new shape should not change the array size, namely - ``np.prod(new_shape)`` should be equal to ``np.prod(self.shape)``. - One shape dimension can be -1. In this case, the value is inferred - from the length of the array and remaining dimensions. + The arguments are the same as for :py:func:`reshape`, with + this array as data. + """ + return reshape(self, *args, **kwargs) + def astype(self, *args, **kwargs): + """Convenience fluent method for :py:func:`cast`. - Returns - ------- - Symbol - A reshaped symbol. + The arguments are the same as for :py:func:`cast`, with + this array as data. + """ + return cast(self, *args, **kwargs) + + def zeros_like(self, *args, **kwargs): + """Convenience fluent method for :py:func:`zeros_like`. + + The arguments are the same as for :py:func:`zeros_like`, with + this array as data. + """ + return zeros_like(self, *args, **kwargs) + + def ones_like(self, *args, **kwargs): + """Convenience fluent method for :py:func:`ones_like`. + + The arguments are the same as for :py:func:`ones_like`, with + this array as data. + """ + return ones_like(self, *args, **kwargs) + + def broadcast_axes(self, *args, **kwargs): + """Convenience fluent method for :py:func:`broadcast_axes`. + + The arguments are the same as for :py:func:`broadcast_axes`, with + this array as data. + """ + return broadcast_axes(self, *args, **kwargs) + + def repeat(self, *args, **kwargs): + """Convenience fluent method for :py:func:`repeat`. + + The arguments are the same as for :py:func:`repeat`, with + this array as data. + """ + return repeat(self, *args, **kwargs) + + def pad(self, *args, **kwargs): + """Convenience fluent method for :py:func:`pad`. + + The arguments are the same as for :py:func:`pad`, with + this array as data. + """ + return pad(self, *args, **kwargs) + + def swapaxes(self, *args, **kwargs): + """Convenience fluent method for :py:func:`swapaxes`. + + The arguments are the same as for :py:func:`swapaxes`, with + this array as data. + """ + return swapaxes(self, *args, **kwargs) + + def split(self, *args, **kwargs): + """Convenience fluent method for :py:func:`split`. + + The arguments are the same as for :py:func:`split`, with + this array as data. + """ + return split(self, *args, **kwargs) + + def slice(self, *args, **kwargs): + """Convenience fluent method for :py:func:`slice`. + + The arguments are the same as for :py:func:`slice`, with + this array as data. + """ + return slice(self, *args, **kwargs) + + def slice_axis(self, *args, **kwargs): + """Convenience fluent method for :py:func:`slice_axis`. + + The arguments are the same as for :py:func:`slice_axis`, with + this array as data. """ - return reshape(self, shape=shape) + return slice_axis(self, *args, **kwargs) + + def take(self, *args, **kwargs): + """Convenience fluent method for :py:func:`take`. + + The arguments are the same as for :py:func:`take`, with + this array as data. + """ + return take(self, *args, **kwargs) + + def one_hot(self, *args, **kwargs): + """Convenience fluent method for :py:func:`one_hot`. + + The arguments are the same as for :py:func:`one_hot`, with + this array as data. + """ + return one_hot(self, *args, **kwargs) + + def pick(self, *args, **kwargs): + """Convenience fluent method for :py:func:`pick`. + + The arguments are the same as for :py:func:`pick`, with + this array as data. + """ + return pick(self, *args, **kwargs) + + def sort(self, *args, **kwargs): + """Convenience fluent method for :py:func:`sort`. + + The arguments are the same as for :py:func:`sort`, with + this array as data. + """ + return sort(self, *args, **kwargs) + + def topk(self, *args, **kwargs): + """Convenience fluent method for :py:func:`topk`. + + The arguments are the same as for :py:func:`topk`, with + this array as data. + """ + return topk(self, *args, **kwargs) + + def argsort(self, *args, **kwargs): + """Convenience fluent method for :py:func:`argsort`. + + The arguments are the same as for :py:func:`argsort`, with + this array as data. + """ + return argsort(self, *args, **kwargs) + + def argmax(self, *args, **kwargs): + """Convenience fluent method for :py:func:`argmax`. + + The arguments are the same as for :py:func:`argmax`, with + this array as data. + """ + return argmax(self, *args, **kwargs) + + def argmin(self, *args, **kwargs): + """Convenience fluent method for :py:func:`argmin`. + + The arguments are the same as for :py:func:`argmin`, with + this array as data. + """ + return argmin(self, *args, **kwargs) + + def clip(self, *args, **kwargs): + """Convenience fluent method for :py:func:`clip`. + + The arguments are the same as for :py:func:`clip`, with + this array as data. + """ + return clip(self, *args, **kwargs) + + def abs(self, *args, **kwargs): + """Convenience fluent method for :py:func:`abs`. + + The arguments are the same as for :py:func:`abs`, with + this array as data. + """ + return abs(self, *args, **kwargs) + + def sign(self, *args, **kwargs): + """Convenience fluent method for :py:func:`sign`. + + The arguments are the same as for :py:func:`sign`, with + this array as data. + """ + return sign(self, *args, **kwargs) + + def flatten(self, *args, **kwargs): + """Convenience fluent method for :py:func:`flatten`. + + The arguments are the same as for :py:func:`flatten`, with + this array as data. + """ + return flatten(self, *args, **kwargs) + + def expand_dims(self, *args, **kwargs): + """Convenience fluent method for :py:func:`expand_dims`. + + The arguments are the same as for :py:func:`expand_dims`, with + this array as data. + """ + return expand_dims(self, *args, **kwargs) + + def broadcast_to(self, *args, **kwargs): + """Convenience fluent method for :py:func:`broadcast_to`. + + The arguments are the same as for :py:func:`broadcast_to`, with + this array as data. + """ + return broadcast_to(self, *args, **kwargs) + + def tile(self, *args, **kwargs): + """Convenience fluent method for :py:func:`tile`. + + The arguments are the same as for :py:func:`tile`, with + this array as data. + """ + return tile(self, *args, **kwargs) + + def transpose(self, *args, **kwargs): + """Convenience fluent method for :py:func:`transpose`. + + The arguments are the same as for :py:func:`transpose`, with + this array as data. + """ + return transpose(self, *args, **kwargs) + + def flip(self, *args, **kwargs): + """Convenience fluent method for :py:func:`flip`. + + The arguments are the same as for :py:func:`flip`, with + this array as data. + """ + return flip(self, *args, **kwargs) + + def sum(self, *args, **kwargs): + """Convenience fluent method for :py:func:`sum`. + + The arguments are the same as for :py:func:`sum`, with + this array as data. + """ + return sum(self, *args, **kwargs) + + def nansum(self, *args, **kwargs): + """Convenience fluent method for :py:func:`nansum`. + + The arguments are the same as for :py:func:`nansum`, with + this array as data. + """ + return nansum(self, *args, **kwargs) + + def prod(self, *args, **kwargs): + """Convenience fluent method for :py:func:`prod`. + + The arguments are the same as for :py:func:`prod`, with + this array as data. + """ + return prod(self, *args, **kwargs) + + def nanprod(self, *args, **kwargs): + """Convenience fluent method for :py:func:`nanprod`. + + The arguments are the same as for :py:func:`nanprod`, with + this array as data. + """ + return nanprod(self, *args, **kwargs) + + def mean(self, *args, **kwargs): + """Convenience fluent method for :py:func:`mean`. + + The arguments are the same as for :py:func:`mean`, with + this array as data. + """ + return mean(self, *args, **kwargs) + + def max(self, *args, **kwargs): + """Convenience fluent method for :py:func:`max`. + + The arguments are the same as for :py:func:`max`, with + this array as data. + """ + return max(self, *args, **kwargs) + + def min(self, *args, **kwargs): + """Convenience fluent method for :py:func:`min`. + + The arguments are the same as for :py:func:`min`, with + this array as data. + """ + return min(self, *args, **kwargs) + + def norm(self, *args, **kwargs): + """Convenience fluent method for :py:func:`norm`. + + The arguments are the same as for :py:func:`norm`, with + this array as data. + """ + return norm(self, *args, **kwargs) + + def round(self, *args, **kwargs): + """Convenience fluent method for :py:func:`round`. + + The arguments are the same as for :py:func:`round`, with + this array as data. + """ + return round(self, *args, **kwargs) + + def rint(self, *args, **kwargs): + """Convenience fluent method for :py:func:`rint`. + + The arguments are the same as for :py:func:`rint`, with + this array as data. + """ + return rint(self, *args, **kwargs) + + def fix(self, *args, **kwargs): + """Convenience fluent method for :py:func:`fix`. + + The arguments are the same as for :py:func:`fix`, with + this array as data. + """ + return fix(self, *args, **kwargs) + + def floor(self, *args, **kwargs): + """Convenience fluent method for :py:func:`floor`. + + The arguments are the same as for :py:func:`floor`, with + this array as data. + """ + return floor(self, *args, **kwargs) + + def ceil(self, *args, **kwargs): + """Convenience fluent method for :py:func:`ceil`. + + The arguments are the same as for :py:func:`ceil`, with + this array as data. + """ + return ceil(self, *args, **kwargs) + + def trunc(self, *args, **kwargs): + """Convenience fluent method for :py:func:`trunc`. + + The arguments are the same as for :py:func:`trunc`, with + this array as data. + """ + return trunc(self, *args, **kwargs) def wait_to_read(self): raise NotImplementedForSymbol(self.wait_to_read, None) @@ -1760,9 +2081,6 @@ def asnumpy(self): def asscalar(self): raise NotImplementedForSymbol(self.asscalar, None) - def astype(self): - raise NotImplementedForSymbol(self.astype, None) - def copy(self): raise NotImplementedForSymbol(self.copy, None) @@ -1779,8 +2097,8 @@ def var(name, attr=None, shape=None, lr_mult=None, wd_mult=None, dtype=None, init=None, stype=None, **kwargs): """Creates a symbolic variable with specified name. - Example usage: - ---------- + Example + ------- >>> data = mx.sym.Variable('data', attr={'a': 'b'}) >>> data @@ -1852,8 +2170,8 @@ def var(name, attr=None, shape=None, lr_mult=None, wd_mult=None, dtype=None, def Group(symbols): """Creates a symbol that contains a collection of other symbols, grouped together. - Example usage: - ---------- + Example + ------- >>> a = mx.sym.Variable('a') >>> b = mx.sym.Variable('b') >>> mx.sym.Group([a,b]) @@ -2180,7 +2498,7 @@ def full(shape, val, dtype=None, **kwargs): dtype = _numpy.float32 return _internal._MulScalar(ones(shape=shape, dtype=dtype, **kwargs), scalar=val) - +# pylint: disable=redefined-outer-name def arange(start, stop=None, step=1.0, repeat=1, name=None, dtype=None): """Returns evenly spaced values within a given interval. diff --git a/tests/python/unittest/test_ndarray.py b/tests/python/unittest/test_ndarray.py index 3e0ac66c168d..f2c6a834cbcd 100644 --- a/tests/python/unittest/test_ndarray.py +++ b/tests/python/unittest/test_ndarray.py @@ -697,6 +697,49 @@ def test_output(): mx.nd.full(shape, 2, out=out) assert_almost_equal(out.asnumpy(), ones.asnumpy() * 2) +def test_ndarray_fluent(): + has_grad = set(['flatten', 'expand_dims', 'flip', 'tile', 'transpose', 'sum', 'nansum', 'prod', + 'nanprod', 'mean', 'max', 'min', 'reshape', 'broadcast_to', 'split', + 'broadcast_axes', 'pad', 'swapaxes', 'slice', 'slice_axis', 'take', + 'one_hot', 'pick', 'sort', 'topk', 'argsort', 'argmax', 'argmin', + 'clip', 'abs' 'sign']) + def check_fluent_regular(func, kwargs, shape=(5, 17, 1)): + with mx.name.NameManager(): + data = mx.nd.random_uniform(shape=shape) + regular = getattr(mx.ndarray, func)(data, **kwargs) + fluent = getattr(data, func)(**kwargs) + if isinstance(regular, list): + for r, f in zip(regular, fluent): + assert almost_equal(r.asnumpy(), f.asnumpy()) + else: + assert almost_equal(regular.asnumpy(), fluent.asnumpy()) + + for func in ['flatten', 'norm', 'round', 'rint', 'fix', 'floor', 'ceil', 'trunc', 'zeros_like', + 'ones_like', 'abs', 'sign']: + check_fluent_regular(func, {}) + + for func in ['expand_dims', 'flip', 'sort', 'topk', 'argsort', 'argmax', 'argmin']: + check_fluent_regular(func, {'axis': 1}) + + check_fluent_regular('one_hot', {'depth': 15}) + check_fluent_regular('tile', {'reps': (1,2)}) + check_fluent_regular('repeat', {'repeats': 3}) + check_fluent_regular('transpose', {'axes': (1,0,2)}) + check_fluent_regular('split', {'axis': 2, 'num_outputs': 3}, shape=(5, 17, 6)) + check_fluent_regular('slice', {'begin': (2, 5, 1), 'end': (4, 7, 6)}, shape=(5, 17, 6)) + check_fluent_regular('slice_axis', {'axis': 1, 'begin': 5, 'end': 7}) + check_fluent_regular('take', {'indices': mx.nd.array([2, 3])}) + check_fluent_regular('pick', {'axis': 1, 'begin': 5, 'end': 7}) + check_fluent_regular('clip', {'a_min': 0.25, 'a_max': 0.75}) + check_fluent_regular('broadcast_axes', {'axis': (2,), 'size': (5,)}) + check_fluent_regular('pad', {'mode': 'constant', 'pad_width': (0,0,0,0,3,0,0,4)}, shape=(5, 17, 2, 3)) + + for func in ['sum', 'nansum', 'prod', 'nanprod', 'mean', 'max', 'min']: + check_fluent_regular(func, {'axis': (1, 2)}) + + check_fluent_regular('reshape', {'shape': (17, 1, 5)}) + check_fluent_regular('broadcast_to', {'shape': (5, 17, 47)}) + if __name__ == '__main__': import nose diff --git a/tests/python/unittest/test_symbol.py b/tests/python/unittest/test_symbol.py index c570325a6b66..4d162ecf6e50 100644 --- a/tests/python/unittest/test_symbol.py +++ b/tests/python/unittest/test_symbol.py @@ -162,12 +162,52 @@ def test_symbol_infer_shape_var(): assert arg_shapes[1] == overwrite_shape assert out_shapes[0] == overwrite_shape -def check_symbol_consistency(sym1, sym2, ctx): +def test_symbol_fluent(): + has_grad = set(['flatten', 'expand_dims', 'flip', 'tile', 'transpose', 'sum', 'nansum', 'prod', + 'nanprod', 'mean', 'max', 'min', 'reshape', 'broadcast_to', 'split', + 'broadcast_axes', 'pad', 'swapaxes', 'slice', 'slice_axis', 'take', + 'one_hot', 'pick', 'sort', 'topk', 'argsort', 'argmax', 'argmin', + 'clip', 'abs' 'sign']) + def check_fluent_regular(func, kwargs, shape=(5, 17, 1)): + with mx.name.NameManager(): + data = mx.symbol.Variable('data') + regular = getattr(mx.symbol, func)(data, name=func+'0', **kwargs) + fluent = getattr(data, func)(**kwargs) + check_symbol_consistency(regular, fluent, {'ctx': mx.context.current_context(), + 'data': shape}, + skip_grad=func not in has_grad) + + for func in ['flatten', 'norm', 'round', 'rint', 'fix', 'floor', 'ceil', 'trunc', 'zeros_like', + 'ones_like', 'abs', 'sign']: + check_fluent_regular(func, {}) + + for func in ['expand_dims', 'flip', 'sort', 'topk', 'argsort', 'argmax', 'argmin']: + check_fluent_regular(func, {'axis': 1}) + + check_fluent_regular('one_hot', {'depth': 15}) + check_fluent_regular('tile', {'reps': (1,2)}) + check_fluent_regular('repeat', {'repeats': 3}) + check_fluent_regular('transpose', {'axes': (1,0,2)}) + check_fluent_regular('split', {'axis': 2, 'num_outputs': 3}, shape=(5, 17, 6)) + check_fluent_regular('slice', {'begin': (2, 5, 1), 'end': (4, 7, 6)}, shape=(5, 17, 6)) + check_fluent_regular('slice_axis', {'axis': 1, 'begin': 5, 'end': 7}) + check_fluent_regular('clip', {'a_min': 0.25, 'a_max': 0.75}) + check_fluent_regular('broadcast_axes', {'axis': (2,), 'size': (5,)}) + check_fluent_regular('pad', {'mode': 'constant', 'pad_width': (0,0,0,0,3,0,0,4)}, shape=(5, 17, 2, 3)) + + for func in ['sum', 'nansum', 'prod', 'nanprod', 'mean', 'max', 'min']: + check_fluent_regular(func, {'axis': (1, 2)}) + + check_fluent_regular('reshape', {'shape': (17, 1, 5)}) + check_fluent_regular('broadcast_to', {'shape': (5, 17, 47)}) + +def check_symbol_consistency(sym1, sym2, ctx, skip_grad=False): assert sym1.list_arguments() == sym2.list_arguments() assert sym1.list_auxiliary_states() == sym2.list_auxiliary_states() assert sym1.list_outputs() == sym2.list_outputs() - mx.test_utils.check_consistency([sym1, sym2], ctx_list=[ctx, ctx]) + mx.test_utils.check_consistency([sym1, sym2], ctx_list=[ctx, ctx], + grad_req='null' if skip_grad else 'write') def test_load_000800(): with mx.AttrScope(ctx_group='stage1'):