From d786f627cd2af445f73ec7faa7ee79910efe2701 Mon Sep 17 00:00:00 2001 From: "Huang, Guangtai" Date: Fri, 17 Apr 2020 14:14:48 +0800 Subject: [PATCH] [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 ++++++- src/api/operator/numpy/np_trace_op.cc | 56 +++++++++++++ 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, 390 insertions(+), 118 deletions(-) create mode 100644 src/api/operator/numpy/np_trace_op.cc diff --git a/benchmark/python/ffi/benchmark_ffi.py b/benchmark/python/ffi/benchmark_ffi.py index c42e1407ab32..818e5a621aeb 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 857b87a7586f..47d7545acfc4 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 - `_ 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 1a66abb1a9be..06b8d5f844e9 100644 --- a/python/mxnet/ndarray/numpy/_op.py +++ b/python/mxnet/ndarray/numpy/_op.py @@ -31,7 +31,7 @@ __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 + `_ 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 076a6b98b953..029bb734db22 100644 --- a/python/mxnet/numpy/multiarray.py +++ b/python/mxnet/numpy/multiarray.py @@ -55,7 +55,7 @@ __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', @@ -1752,13 +1752,10 @@ def expand_dims(self, *args, **kwargs): # pylint: disable=arguments-differ,unus """ 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.""" @@ -1769,7 +1766,7 @@ def transpose(self, *axes): # pylint: disable=arguments-differ 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`. @@ -5499,7 +5496,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.], @@ -5521,6 +5518,96 @@ def tile(A, reps): return _mx_nd_np.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 + `_ 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""" diff --git a/python/mxnet/symbol/numpy/_symbol.py b/python/mxnet/symbol/numpy/_symbol.py index cc6151ed1a1c..bd4f25232705 100644 --- a/python/mxnet/symbol/numpy/_symbol.py +++ b/python/mxnet/symbol/numpy/_symbol.py @@ -37,7 +37,7 @@ __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', @@ -668,7 +668,7 @@ def transpose(self, *axes): # pylint: disable=arguments-differ 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`. @@ -2323,6 +2323,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 998823d37db8..58ee563d8e80 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 #include @@ -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(&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/numpy/np_trace_op.cc b/src/api/operator/numpy/np_trace_op.cc new file mode 100644 index 000000000000..2979d21dbdc9 --- /dev/null +++ b/src/api/operator/numpy/np_trace_op.cc @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * 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 + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/*! + * \file np_trace_op.cc + * \brief Implementation of the API of functions in src/operator/numpy/np_trace_op.cc + */ +#include +#include +#include "../utils.h" +#include "../../../operator/numpy/np_trace_op-inl.h" + +namespace mxnet { + +MXNET_REGISTER_API("_npi.trace") +.set_body([](runtime::MXNetArgs args, runtime::MXNetRetValue* ret) { + using namespace runtime; + const nnvm::Op* op = Op::Get("_npi_trace"); + nnvm::NodeAttrs attrs; + 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(&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; + int num_outputs = out != nullptr; + auto ndoutputs = Invoke(op, &attrs, num_inputs, inputs, &num_outputs, outputs); + if (out) { + *ret = PythonArg(4); + } else { + *ret = ndoutputs[0]; + } +}); + +} // namespace mxnet diff --git a/src/api/operator/tensor/matrix_op.cc b/src/api/operator/tensor/matrix_op.cc index ed91b091cc39..61344286372e 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(1, args[1].operator int64_t()); + } else { + param.reps = Tuple(args[1].operator ObjectRef()); + } + attrs.parsed = std::move(param); + attrs.op = op; + SetAttrDict(&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 09eb10c2982f..4d73faef5b27 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 { .describe("By default, reverse the dimensions, otherwise permute " "the axes according to the values given."); } + void SetAttrDict(std::unordered_map* dict) { + std::ostringstream axes_s; + axes_s << axes; + (*dict)["axes"] = axes_s.str(); + } }; struct NumpyVstackParam : public dmlc::Parameter { diff --git a/src/operator/numpy/np_matrix_op.cc b/src/operator/numpy/np_matrix_op.cc index f47a57566d69..902db89cc54d 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) @@ -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()); } }) diff --git a/src/operator/numpy/np_matrix_op.cu b/src/operator/numpy/np_matrix_op.cu index f919bb5f9c10..7b525d14b29a 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", NumpyTranspose); 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 741c20b61d80..ede7d37ee686 100644 --- a/src/operator/numpy/np_trace_op-inl.h +++ b/src/operator/numpy/np_trace_op-inl.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include "../mxnet_op.h" @@ -54,6 +55,15 @@ struct NumpyTraceParam: public dmlc::Parameter { .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* 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 diff --git a/src/operator/numpy/np_trace_op.cc b/src/operator/numpy/np_trace_op.cc index d97ac3040384..e6a120195925 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("FInferShape", NumpyTraceOpShape) .set_attr("FInferType", ElemwiseType<1, 1>) .set_attr("FCompute", NumpyTraceOpForward) -.set_attr("FGradient", ElemwiseGradUseNone{"_backward_np_trace"}) +.set_attr("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) .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 220e4ae62a59..5ec29137d551 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", NumpyTraceOpForward); -NNVM_REGISTER_OP(_backward_np_trace) +NNVM_REGISTER_OP(_backward_npi_trace) .set_attr("FCompute", NumpyTraceOpBackward); } // namespace op diff --git a/src/operator/tensor/matrix_op-inl.h b/src/operator/tensor/matrix_op-inl.h index 821fa8587081..19d713d621c0 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 { " 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* dict) { + std::ostringstream reps_s; + reps_s << reps; + (*dict)["reps"] = reps_s.str(); + } }; inline bool TileOpShape(const nnvm::NodeAttrs& attrs,