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 cf93bdc [Numpy] New FFIs for Operator: tile, trace, transpose (#18017) cf93bdc is described below commit cf93bdc3efc380180d74385d9e91c5034e0d7273 Author: Huang, Guangtai <guang...@amazon.com> AuthorDate: Fri Apr 17 14:14:48 2020 +0800 [Numpy] New FFIs for Operator: tile, trace, transpose (#18017) * init * fix typo * transpose * add benchmark * fix lint --- benchmark/python/ffi/benchmark_ffi.py | 3 + python/mxnet/_numpy_op_doc.py | 90 +---------------- python/mxnet/ndarray/numpy/_op.py | 101 ++++++++++++++++++- python/mxnet/numpy/multiarray.py | 107 +++++++++++++++++++-- python/mxnet/symbol/numpy/_symbol.py | 59 +++++++++++- src/api/operator/numpy/np_matrix_op.cc | 29 +++++- .../{tensor/matrix_op.cc => numpy/np_trace_op.cc} | 49 ++++------ src/api/operator/tensor/matrix_op.cc | 25 ++++- src/operator/numpy/np_matrix_op-inl.h | 5 + src/operator/numpy/np_matrix_op.cc | 6 +- src/operator/numpy/np_matrix_op.cu | 2 +- src/operator/numpy/np_trace_op-inl.h | 10 ++ src/operator/numpy/np_trace_op.cc | 6 +- src/operator/numpy/np_trace_op.cu | 4 +- src/operator/tensor/matrix_op-inl.h | 5 + 15 files changed, 351 insertions(+), 150 deletions(-) diff --git a/benchmark/python/ffi/benchmark_ffi.py b/benchmark/python/ffi/benchmark_ffi.py index c42e140..818e5a6 100644 --- a/benchmark/python/ffi/benchmark_ffi.py +++ b/benchmark/python/ffi/benchmark_ffi.py @@ -83,6 +83,9 @@ def prepare_workloads(): OpArgMngr.add_workload("linalg.tensorinv", pool['1x1'], ind=2) OpArgMngr.add_workload("linalg.norm", pool['3x3']) OpArgMngr.add_workload("linalg.tensorsolve", pool['1x1x1'], pool['1x1x1'], (2, 0, 1)) + OpArgMngr.add_workload("tile", pool['2x2'], 1) + OpArgMngr.add_workload("trace", pool['2x2']) + OpArgMngr.add_workload("transpose", pool['2x2']) OpArgMngr.add_workload("split", pool['3x3'], (0, 1, 2), axis=1) OpArgMngr.add_workload("argmax", pool['3x2'], axis=-1) OpArgMngr.add_workload("argmin", pool['3x2'], axis=-1) diff --git a/python/mxnet/_numpy_op_doc.py b/python/mxnet/_numpy_op_doc.py index 857b87a..47d7545 100644 --- a/python/mxnet/_numpy_op_doc.py +++ b/python/mxnet/_numpy_op_doc.py @@ -37,7 +37,7 @@ def _npx_nonzero(a): """ Return the indices of the elements that are non-zero. - Returns a ndarray with ndim is 2. Each row contains the indices + Returns a ndarray with ndim is 2. Each row contains the indices of the non-zero elements. The values in `a` are always tested and returned in row-major, C-style order. @@ -127,48 +127,6 @@ def _np_repeat(a, repeats, axis=None): pass -def _np_transpose(a, axes=None): - """ - Permute the dimensions of an array. - - Parameters - ---------- - a : ndarray - Input array. - axes : list of ints, optional - By default, reverse the dimensions, - otherwise permute the axes according to the values given. - - Returns - ------- - p : ndarray - a with its axes permuted. - - Notes - ----- - This function differs from the original `numpy.transpose - <https://docs.scipy.org/doc/numpy/reference/generated/numpy.transpose.html>`_ in - the following way(s): - - - only ndarray is accepted as valid input, python iterables are not supported - - the operator always returns an `ndarray` that does not share the memory with the input - - Examples - -------- - >>> x = np.arange(4).reshape((2,2)) - >>> x - array([[0., 1.], - [2., 3.]]) - >>> np.transpose(x) - array([[0., 2.], - [1., 3.]]) - >>> x = np.ones((1, 2, 3)) - >>> np.transpose(x, (1, 0, 2)).shape - (2, 1, 3) - """ - pass - - def _np_dot(a, b, out=None): """ Dot product of two arrays. Specifically, @@ -339,52 +297,6 @@ def _np_reshape(a, newshape, order='C', out=None): """ -def _np_trace(a, offset=0, axis1=0, axis2=1, out=None): - """ - Return the sum along diagonals of the array. - If `a` is 2-D, the sum along its diagonal with the given offset - is returned, i.e., the sum of elements ``a[i,i+offset]`` for all i. - If `a` has more than two dimensions, then the axes specified by axis1 and - axis2 are used to determine the 2-D sub-arrays whose traces are returned. - The shape of the resulting array is the same as that of `a` with `axis1` - and `axis2` removed. - - Parameters - ---------- - a : ndarray - Input array, from which the diagonals are taken. - offset : int, optional - Offset of the diagonal from the main diagonal. Can be both positive - and negative. Defaults to 0. - axis1, axis2 : int, optional - Axes to be used as the first and second axis of the 2-D sub-arrays - from which the diagonals should be taken. Defaults are the first two - axes of `a`. - out : ndarray, optional - Array into which the output is placed. It must be of the right shape - and right type to hold the output. - - Returns - ------- - sum_along_diagonals : ndarray - If `a` is 2-D, the sum along the diagonal is returned. If `a` has - larger dimensions, then an array of sums along diagonals is returned. - - Examples - -------- - >>> a = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) - >>> np.trace(a) - array(3.) - >>> a = np.arange(8).reshape((2, 2, 2)) - >>> np.trace(a) - array([6., 8.]) - >>> a = np.arange(24).reshape((2, 2, 2, 3)) - >>> np.trace(a).shape - (2, 3) - """ - pass - - def _np_squeeze(a, axis=None, out=None): """ Remove single-dimensional entries from the shape of an array. diff --git a/python/mxnet/ndarray/numpy/_op.py b/python/mxnet/ndarray/numpy/_op.py index 1a66abb..06b8d5f 100644 --- a/python/mxnet/ndarray/numpy/_op.py +++ b/python/mxnet/ndarray/numpy/_op.py @@ -31,7 +31,7 @@ from ..ndarray import NDArray __all__ = ['shape', 'zeros', 'zeros_like', 'ones', 'ones_like', 'full', 'full_like', 'empty_like', 'invert', 'delete', 'add', 'broadcast_to', 'subtract', 'multiply', 'divide', 'mod', 'remainder', 'fmod', - 'power', 'bitwise_not', + 'power', 'bitwise_not', 'trace', 'transpose', 'arctan2', 'sin', 'cos', 'tan', 'sinh', 'cosh', 'tanh', 'log10', 'sqrt', 'cbrt', 'abs', 'insert', 'fabs', 'absolute', 'exp', 'expm1', 'arcsin', 'arccos', 'arctan', 'sign', 'log', 'degrees', 'log2', 'matmul', 'log1p', 'rint', 'radians', 'reciprocal', 'square', 'negative', 'fix', 'ceil', 'floor', 'histogram', @@ -2095,6 +2095,53 @@ def triu(m, k=0): return _api_internal.triu(m, k) +@set_module('mxnet.ndarray.numpy') +def trace(a, offset=0, axis1=0, axis2=1, out=None): + """ + Return the sum along diagonals of the array. + If `a` is 2-D, the sum along its diagonal with the given offset + is returned, i.e., the sum of elements ``a[i,i+offset]`` for all i. + If `a` has more than two dimensions, then the axes specified by axis1 and + axis2 are used to determine the 2-D sub-arrays whose traces are returned. + The shape of the resulting array is the same as that of `a` with `axis1` + and `axis2` removed. + + Parameters + ---------- + a : ndarray + Input array, from which the diagonals are taken. + offset : int, optional + Offset of the diagonal from the main diagonal. Can be both positive + and negative. Defaults to 0. + axis1, axis2 : int, optional + Axes to be used as the first and second axis of the 2-D sub-arrays + from which the diagonals should be taken. Defaults are the first two + axes of `a`. + out : ndarray, optional + Array into which the output is placed. It must be of the right shape + and right type to hold the output. + + Returns + ------- + sum_along_diagonals : ndarray + If `a` is 2-D, the sum along the diagonal is returned. If `a` has + larger dimensions, then an array of sums along diagonals is returned. + + Examples + -------- + >>> a = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + >>> np.trace(a) + array(3.) + >>> a = np.arange(8).reshape((2, 2, 2)) + >>> np.trace(a) + array([6., 8.]) + >>> a = np.arange(24).reshape((2, 2, 2, 3)) + >>> np.trace(a).shape + (2, 3) + """ + return _api_internal.trace(a, offset, axis1, axis2, out) + + def _unary_func_helper(x, fn_array, fn_scalar, out=None, **kwargs): """Helper function for unary operators with kwargs. @@ -3748,7 +3795,7 @@ def tile(A, reps): >>> np.tile(b, 2) array([[1., 2., 1., 2.], [3., 4., 3., 4.]]) - >>> np.(b, (2, 1)) + >>> np.tile(b, (2, 1)) array([[1., 2.], [3., 4.], [1., 2.], @@ -3767,7 +3814,55 @@ def tile(A, reps): array([2, 2, 2]) # repeating integer `2` """ - return _unary_func_helper(A, _npi.tile, _np.tile, reps=reps) + if isinstance(A, numeric_types): + return _np.tile(A, reps) + elif isinstance(A, NDArray): + return _api_internal.tile(A, reps) + else: + raise TypeError('type {} not supported'.format(str(type(A)))) + + +@set_module('mxnet.ndarray.numpy') +def transpose(a, axes=None): + """ + Permute the dimensions of an array. + + Parameters + ---------- + a : ndarray + Input array. + axes : list of ints, optional + By default, reverse the dimensions, + otherwise permute the axes according to the values given. + + Returns + ------- + p : ndarray + a with its axes permuted. + + Notes + ----- + This function differs from the original `numpy.transpose + <https://docs.scipy.org/doc/numpy/reference/generated/numpy.transpose.html>`_ in + the following way(s): + + - only ndarray is accepted as valid input, python iterables are not supported + - the operator always returns an `ndarray` that does not share the memory with the input + + Examples + -------- + >>> x = np.arange(4).reshape((2,2)) + >>> x + array([[0., 1.], + [2., 3.]]) + >>> np.transpose(x) + array([[0., 2.], + [1., 3.]]) + >>> x = np.ones((1, 2, 3)) + >>> np.transpose(x, (1, 0, 2)).shape + (2, 1, 3) + """ + return _api_internal.transpose(a, axes) # pylint: disable=redefined-outer-name diff --git a/python/mxnet/numpy/multiarray.py b/python/mxnet/numpy/multiarray.py index 2d6a788..99a6744 100644 --- a/python/mxnet/numpy/multiarray.py +++ b/python/mxnet/numpy/multiarray.py @@ -55,7 +55,7 @@ from . import fallback __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', + 'delete', 'trace', 'transpose', 'arctan2', 'sin', 'cos', 'tan', 'sinh', 'cosh', 'tanh', 'log10', 'invert', 'sqrt', 'cbrt', 'abs', 'absolute', 'fabs', 'exp', 'expm1', 'arcsin', 'arccos', 'arctan', 'sign', 'log', 'degrees', 'log2', 'log1p', 'rint', 'radians', 'reciprocal', 'square', 'negative', 'histogram', @@ -1730,13 +1730,10 @@ class ndarray(NDArray): """ raise AttributeError('mxnet.numpy.ndarray object has no attribute expand_dims') - 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. - """ - raise AttributeError('mxnet.numpy.ndarray object has no attribute tile') + def tile(self, reps): # pylint: disable=arguments-differ + """Construct an array by repeating A the number of times given by reps. + Refer to `mxnet.numpy.tile` for full documentation.""" + return tile(self, reps=reps) def transpose(self, *axes): # pylint: disable=arguments-differ """Permute the dimensions of an array.""" @@ -1747,7 +1744,7 @@ class ndarray(NDArray): axes = axes[0] elif axes[0] is None: axes = None - return _mx_np_op.transpose(self, axes=axes) + return transpose(self, axes=axes) def flip(self, *args, **kwargs): """Convenience fluent method for :py:func:`flip`. @@ -5477,7 +5474,7 @@ def tile(A, reps): >>> np.tile(b, 2) array([[1., 2., 1., 2.], [3., 4., 3., 4.]]) - >>> np.(b, (2, 1)) + >>> np.tile(b, (2, 1)) array([[1., 2.], [3., 4.], [1., 2.], @@ -5500,6 +5497,96 @@ def tile(A, reps): @set_module('mxnet.numpy') +def trace(a, offset=0, axis1=0, axis2=1, out=None): + """ + Return the sum along diagonals of the array. + If `a` is 2-D, the sum along its diagonal with the given offset + is returned, i.e., the sum of elements ``a[i,i+offset]`` for all i. + If `a` has more than two dimensions, then the axes specified by axis1 and + axis2 are used to determine the 2-D sub-arrays whose traces are returned. + The shape of the resulting array is the same as that of `a` with `axis1` + and `axis2` removed. + + Parameters + ---------- + a : ndarray + Input array, from which the diagonals are taken. + offset : int, optional + Offset of the diagonal from the main diagonal. Can be both positive + and negative. Defaults to 0. + axis1, axis2 : int, optional + Axes to be used as the first and second axis of the 2-D sub-arrays + from which the diagonals should be taken. Defaults are the first two + axes of `a`. + out : ndarray, optional + Array into which the output is placed. It must be of the right shape + and right type to hold the output. + + Returns + ------- + sum_along_diagonals : ndarray + If `a` is 2-D, the sum along the diagonal is returned. If `a` has + larger dimensions, then an array of sums along diagonals is returned. + + Examples + -------- + >>> a = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + >>> np.trace(a) + array(3.) + >>> a = np.arange(8).reshape((2, 2, 2)) + >>> np.trace(a) + array([6., 8.]) + >>> a = np.arange(24).reshape((2, 2, 2, 3)) + >>> np.trace(a).shape + (2, 3) + """ + return _mx_nd_np.trace(a, offset, axis1, axis2, out) + + +@set_module('mxnet.numpy') +def transpose(a, axes=None): + """ + Permute the dimensions of an array. + + Parameters + ---------- + a : ndarray + Input array. + axes : list of ints, optional + By default, reverse the dimensions, + otherwise permute the axes according to the values given. + + Returns + ------- + p : ndarray + a with its axes permuted. + + Notes + ----- + This function differs from the original `numpy.transpose + <https://docs.scipy.org/doc/numpy/reference/generated/numpy.transpose.html>`_ in + the following way(s): + + - only ndarray is accepted as valid input, python iterables are not supported + - the operator always returns an `ndarray` that does not share the memory with the input + + Examples + -------- + >>> x = np.arange(4).reshape((2,2)) + >>> x + array([[0., 1.], + [2., 3.]]) + >>> np.transpose(x) + array([[0., 2.], + [1., 3.]]) + >>> x = np.ones((1, 2, 3)) + >>> np.transpose(x, (1, 0, 2)).shape + (2, 1, 3) + """ + return _mx_nd_np.transpose(a, axes) + + +@set_module('mxnet.numpy') def tril(m, k=0): r""" Lower triangle of an array. diff --git a/python/mxnet/symbol/numpy/_symbol.py b/python/mxnet/symbol/numpy/_symbol.py index 8b31c8e..5951865 100644 --- a/python/mxnet/symbol/numpy/_symbol.py +++ b/python/mxnet/symbol/numpy/_symbol.py @@ -37,7 +37,7 @@ except ImportError: __all__ = ['zeros', 'zeros_like', 'ones', 'ones_like', 'full', 'full_like', 'empty_like', 'bitwise_not', 'invert', 'delete', 'add', 'broadcast_to', 'subtract', 'multiply', 'divide', 'mod', 'remainder', 'fmod', - 'power', 'arctan2', + 'power', 'arctan2', 'trace', 'transpose', 'sin', 'cos', 'tan', 'sinh', 'cosh', 'tanh', 'log10', 'sqrt', 'cbrt', 'abs', 'absolute', 'fabs', 'exp', 'expm1', 'arcsin', 'arccos', 'arctan', 'sign', 'log', 'degrees', 'log2', 'log1p', 'matmul', 'median', 'rint', 'radians', 'reciprocal', 'square', 'negative', 'fix', 'ceil', 'floor', 'histogram', 'insert', @@ -653,7 +653,7 @@ class _Symbol(Symbol): axes = axes[0] elif axes[0] is None: axes = None - return _mx_np_op.transpose(self, axes=axes) + return transpose(self, axes=axes) def flip(self, *args, **kwargs): """Convenience fluent method for :py:func:`flip`. @@ -2308,6 +2308,61 @@ def tril_indices(n, k=0, m=None): return _npi.tril_indices(n, k, m) +@set_module('mxnet.symbol.numpy') +def trace(a, offset=0, axis1=0, axis2=1, out=None): + """ + Return the sum along diagonals of the array. + If `a` is 2-D, the sum along its diagonal with the given offset + is returned, i.e., the sum of elements ``a[i,i+offset]`` for all i. + If `a` has more than two dimensions, then the axes specified by axis1 and + axis2 are used to determine the 2-D sub-arrays whose traces are returned. + The shape of the resulting array is the same as that of `a` with `axis1` + and `axis2` removed. + + Parameters + ---------- + a : _Symbol + Input array, from which the diagonals are taken. + offset : int, optional + Offset of the diagonal from the main diagonal. Can be both positive + and negative. Defaults to 0. + axis1, axis2 : int, optional + Axes to be used as the first and second axis of the 2-D sub-arrays + from which the diagonals should be taken. Defaults are the first two + axes of `a`. + out : _Symbol + Dummy parameter to keep the consistency with the ndarray counterpart. + + Returns + ------- + sum_along_diagonals : _Symbol + If `a` is 2-D, the sum along the diagonal is returned. If `a` has + larger dimensions, then an array of sums along diagonals is returned. + """ + return _npi.trace(a, offset=offset, axis1=axis1, axis2=axis2, out=out) + + +@set_module('mxnet.symbol.numpy') +def transpose(a, axes=None): + """ + Permute the dimensions of an array. + + Parameters + ---------- + a : _Symbol + Input array. + axes : list of ints, optional + By default, reverse the dimensions, + otherwise permute the axes according to the values given. + + Returns + ------- + p : _Symbol + a with its axes permuted. + """ + return _npi.transpose(a, axes=axes) + + def _unary_func_helper(x, fn_array, fn_scalar, out=None, **kwargs): """Helper function for unary operators. diff --git a/src/api/operator/numpy/np_matrix_op.cc b/src/api/operator/numpy/np_matrix_op.cc index 998823d..58ee563 100644 --- a/src/api/operator/numpy/np_matrix_op.cc +++ b/src/api/operator/numpy/np_matrix_op.cc @@ -6,9 +6,9 @@ * to you 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 @@ -19,7 +19,7 @@ /*! * \file np_matrix_op.cc - * \brief Implementation of the API of functions in src/operator/tensor/matrix_op.cc + * \brief Implementation of the API of functions in src/operator/numpy/np_matrix_op.cc */ #include <mxnet/api_registry.h> #include <mxnet/runtime/packed_func.h> @@ -31,6 +31,29 @@ namespace mxnet { +MXNET_REGISTER_API("_npi.transpose") +.set_body([](runtime::MXNetArgs args, runtime::MXNetRetValue* ret) { + using namespace runtime; + static const nnvm::Op* op = Op::Get("_npi_transpose"); + nnvm::NodeAttrs attrs; + op::NumpyTransposeParam param; + if (args[1].type_code() == kNull) { + param.axes = TShape(-1, 0); + } else if (args[1].type_code() == kDLInt) { + param.axes = TShape(1, args[1].operator int64_t()); + } else { + param.axes = TShape(args[1].operator ObjectRef()); + } + attrs.parsed = std::move(param); + attrs.op = op; + SetAttrDict<op::NumpyTransposeParam>(&attrs); + NDArray* inputs[] = {args[0].operator mxnet::NDArray*()}; + int num_inputs = 1; + int num_outputs = 0; + auto ndoutputs = Invoke(op, &attrs, num_inputs, inputs, &num_outputs, nullptr); + *ret = ndoutputs[0]; +}); + MXNET_REGISTER_API("_npi.expand_dims") .set_body([](runtime::MXNetArgs args, runtime::MXNetRetValue* ret) { using namespace runtime; diff --git a/src/api/operator/tensor/matrix_op.cc b/src/api/operator/numpy/np_trace_op.cc similarity index 61% copy from src/api/operator/tensor/matrix_op.cc copy to src/api/operator/numpy/np_trace_op.cc index ed91b09..2979d21 100644 --- a/src/api/operator/tensor/matrix_op.cc +++ b/src/api/operator/numpy/np_trace_op.cc @@ -6,9 +6,9 @@ * to you 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 @@ -18,51 +18,36 @@ */ /*! - * \file matrix_op.cc - * \brief Implementation of the API of functions in src/operator/tensor/matrix_op.cc + * \file np_trace_op.cc + * \brief Implementation of the API of functions in src/operator/numpy/np_trace_op.cc */ #include <mxnet/api_registry.h> #include <mxnet/runtime/packed_func.h> #include "../utils.h" -#include "../../../operator/tensor/matrix_op-inl.h" +#include "../../../operator/numpy/np_trace_op-inl.h" namespace mxnet { -MXNET_REGISTER_API("_npi.clip") +MXNET_REGISTER_API("_npi.trace") .set_body([](runtime::MXNetArgs args, runtime::MXNetRetValue* ret) { using namespace runtime; - const nnvm::Op* op = Op::Get("_npi_clip"); + const nnvm::Op* op = Op::Get("_npi_trace"); nnvm::NodeAttrs attrs; - op::ClipParam param; - NDArray* inputs[1]; - - if (args[0].type_code() != kNull) { - inputs[0] = args[0].operator mxnet::NDArray *(); - } - - if (args[1].type_code() != kNull) { - param.a_min = args[1].operator double(); - } else { - param.a_min = -INFINITY; - } - - if (args[2].type_code() != kNull) { - param.a_max = args[2].operator double(); - } else { - param.a_max = INFINITY; - } - + op::NumpyTraceParam param; + param.offset = args[1].operator int64_t(); + param.axis1 = args[2].operator int64_t(); + param.axis2 = args[3].operator int64_t(); attrs.parsed = param; attrs.op = op; - SetAttrDict<op::ClipParam>(&attrs); - - NDArray* out = args[3].operator mxnet::NDArray*(); + SetAttrDict<op::NumpyTraceParam>(&attrs); + NDArray* inputs[] = {args[0].operator mxnet::NDArray*()}; + int num_inputs = 1; + NDArray* out = args[4].operator mxnet::NDArray*(); NDArray** outputs = out == nullptr ? nullptr : &out; - // set the number of outputs provided by the `out` arugment int num_outputs = out != nullptr; - auto ndoutputs = Invoke(op, &attrs, 1, inputs, &num_outputs, outputs); + auto ndoutputs = Invoke(op, &attrs, num_inputs, inputs, &num_outputs, outputs); if (out) { - *ret = PythonArg(3); + *ret = PythonArg(4); } else { *ret = ndoutputs[0]; } diff --git a/src/api/operator/tensor/matrix_op.cc b/src/api/operator/tensor/matrix_op.cc index ed91b09..6134428 100644 --- a/src/api/operator/tensor/matrix_op.cc +++ b/src/api/operator/tensor/matrix_op.cc @@ -6,9 +6,9 @@ * to you 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 @@ -68,4 +68,25 @@ MXNET_REGISTER_API("_npi.clip") } }); +MXNET_REGISTER_API("_npi.tile") +.set_body([](runtime::MXNetArgs args, runtime::MXNetRetValue* ret) { + using namespace runtime; + const nnvm::Op* op = Op::Get("_npi_tile"); + nnvm::NodeAttrs attrs; + op::TileParam param; + if (args[1].type_code() == kDLInt) { + param.reps = Tuple<int>(1, args[1].operator int64_t()); + } else { + param.reps = Tuple<int>(args[1].operator ObjectRef()); + } + attrs.parsed = std::move(param); + attrs.op = op; + SetAttrDict<op::TileParam>(&attrs); + int num_outputs = 0; + NDArray* inputs[] = {args[0].operator mxnet::NDArray*()}; + int num_inputs = 1; + auto ndoutputs = Invoke(op, &attrs, num_inputs, inputs, &num_outputs, nullptr); + *ret = ndoutputs[0]; +}); + } // namespace mxnet diff --git a/src/operator/numpy/np_matrix_op-inl.h b/src/operator/numpy/np_matrix_op-inl.h index 09eb10c..4d73fae 100644 --- a/src/operator/numpy/np_matrix_op-inl.h +++ b/src/operator/numpy/np_matrix_op-inl.h @@ -47,6 +47,11 @@ struct NumpyTransposeParam : public dmlc::Parameter<NumpyTransposeParam> { .describe("By default, reverse the dimensions, otherwise permute " "the axes according to the values given."); } + void SetAttrDict(std::unordered_map<std::string, std::string>* dict) { + std::ostringstream axes_s; + axes_s << axes; + (*dict)["axes"] = axes_s.str(); + } }; struct NumpyVstackParam : public dmlc::Parameter<NumpyVstackParam> { diff --git a/src/operator/numpy/np_matrix_op.cc b/src/operator/numpy/np_matrix_op.cc index f47a575..902db89 100644 --- a/src/operator/numpy/np_matrix_op.cc +++ b/src/operator/numpy/np_matrix_op.cc @@ -105,7 +105,7 @@ bool NumpyTransposeShape(const nnvm::NodeAttrs& attrs, return shape_is_known(*in_attrs) && shape_is_known(*out_attrs); } -NNVM_REGISTER_OP(_np_transpose) +NNVM_REGISTER_OP(_npi_transpose) .set_num_inputs(1) .set_num_outputs(1) .set_attr_parser(ParamParser<NumpyTransposeParam>) @@ -126,9 +126,9 @@ NNVM_REGISTER_OP(_np_transpose) } std::ostringstream os; os << axes; - return MakeNonlossGradNode("_np_transpose", n, ograds, {}, {{"axes", os.str()}}); + return MakeNonlossGradNode("_npi_transpose", n, ograds, {}, {{"axes", os.str()}}); } else { - return MakeNonlossGradNode("_np_transpose", n, ograds, {}, + return MakeNonlossGradNode("_npi_transpose", n, ograds, {}, std::unordered_map<std::string, std::string>()); } }) diff --git a/src/operator/numpy/np_matrix_op.cu b/src/operator/numpy/np_matrix_op.cu index f919bb5..7b525d1 100644 --- a/src/operator/numpy/np_matrix_op.cu +++ b/src/operator/numpy/np_matrix_op.cu @@ -29,7 +29,7 @@ namespace mxnet { namespace op { -NNVM_REGISTER_OP(_np_transpose) +NNVM_REGISTER_OP(_npi_transpose) .set_attr<FCompute>("FCompute<gpu>", NumpyTranspose<gpu>); NNVM_REGISTER_OP(_np_reshape) diff --git a/src/operator/numpy/np_trace_op-inl.h b/src/operator/numpy/np_trace_op-inl.h index 741c20b..ede7d37 100644 --- a/src/operator/numpy/np_trace_op-inl.h +++ b/src/operator/numpy/np_trace_op-inl.h @@ -28,6 +28,7 @@ #include <dmlc/parameter.h> #include <mxnet/operator_util.h> #include <vector> +#include <string> #include <utility> #include <algorithm> #include "../mxnet_op.h" @@ -54,6 +55,15 @@ struct NumpyTraceParam: public dmlc::Parameter<NumpyTraceParam> { .describe("Axes to be used as the second axis of the 2-D sub-arrays " "from which the diagonals should be taken. Defaults to 1."); } + void SetAttrDict(std::unordered_map<std::string, std::string>* dict) { + std::ostringstream offset_s, axis1_s, axis2_s; + offset_s << offset; + axis1_s << axis1; + axis2_s << axis2; + (*dict)["offset"] = offset_s.str(); + (*dict)["axis1"] = axis1_s.str(); + (*dict)["axis2"] = axis2_s.str(); + } }; template<int ndim, int req, bool back> diff --git a/src/operator/numpy/np_trace_op.cc b/src/operator/numpy/np_trace_op.cc index d97ac30..e6a1201 100644 --- a/src/operator/numpy/np_trace_op.cc +++ b/src/operator/numpy/np_trace_op.cc @@ -54,7 +54,7 @@ inline bool NumpyTraceOpShape(const nnvm::NodeAttrs& attrs, DMLC_REGISTER_PARAMETER(NumpyTraceParam); -NNVM_REGISTER_OP(_np_trace) +NNVM_REGISTER_OP(_npi_trace) .describe(R"code(Computes the sum of the diagonal elements of a matrix. Input is a tensor *A* of dimension *n >= 2*. @@ -83,11 +83,11 @@ Examples:: .set_attr<mxnet::FInferShape>("FInferShape", NumpyTraceOpShape) .set_attr<nnvm::FInferType>("FInferType", ElemwiseType<1, 1>) .set_attr<FCompute>("FCompute<cpu>", NumpyTraceOpForward<cpu>) -.set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseNone{"_backward_np_trace"}) +.set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseNone{"_backward_npi_trace"}) .add_argument("data", "NDArray-or-Symbol", "Input ndarray") .add_arguments(NumpyTraceParam::__FIELDS__()); -NNVM_REGISTER_OP(_backward_np_trace) +NNVM_REGISTER_OP(_backward_npi_trace) .set_attr_parser(ParamParser<NumpyTraceParam>) .set_num_inputs(1) .set_num_outputs(1) diff --git a/src/operator/numpy/np_trace_op.cu b/src/operator/numpy/np_trace_op.cu index 220e4ae..5ec2913 100644 --- a/src/operator/numpy/np_trace_op.cu +++ b/src/operator/numpy/np_trace_op.cu @@ -26,10 +26,10 @@ namespace mxnet { namespace op { -NNVM_REGISTER_OP(_np_trace) +NNVM_REGISTER_OP(_npi_trace) .set_attr<FCompute>("FCompute<gpu>", NumpyTraceOpForward<gpu>); -NNVM_REGISTER_OP(_backward_np_trace) +NNVM_REGISTER_OP(_backward_npi_trace) .set_attr<FCompute>("FCompute<gpu>", NumpyTraceOpBackward<gpu>); } // namespace op diff --git a/src/operator/tensor/matrix_op-inl.h b/src/operator/tensor/matrix_op-inl.h index 821fa85..19d713d 100644 --- a/src/operator/tensor/matrix_op-inl.h +++ b/src/operator/tensor/matrix_op-inl.h @@ -1925,6 +1925,11 @@ struct TileParam : public dmlc::Parameter<TileParam> { " If a.ndim < d, a is promoted to be d-dimensional by prepending new axes." " If a.ndim > d, reps is promoted to a.ndim by pre-pending 1's to it."); } + void SetAttrDict(std::unordered_map<std::string, std::string>* dict) { + std::ostringstream reps_s; + reps_s << reps; + (*dict)["reps"] = reps_s.str(); + } }; inline bool TileOpShape(const nnvm::NodeAttrs& attrs,