From 8115b46cc627e57a80b0780896f3f174179fb9a5 Mon Sep 17 00:00:00 2001 From: barry-jin Date: Fri, 19 Mar 2021 11:18:08 -0700 Subject: [PATCH 1/9] fix reshape and mean --- python/mxnet/base.py | 12 ++++++++++-- python/mxnet/numpy/multiarray.py | 8 ++++---- .../operator/numpy/np_broadcast_reduce_op_value.cc | 2 ++ 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/python/mxnet/base.py b/python/mxnet/base.py index d905ab06a472..15db63e0bff2 100644 --- a/python/mxnet/base.py +++ b/python/mxnet/base.py @@ -790,6 +790,7 @@ def write_all_str(module_file, module_all_list): _NP_OP_PREFIX = '_np_' _NP_OP_SUBMODULE_LIST = ['_random_', '_linalg_'] +_NP_OP_IMPLEMENTED_SET = {'_np_reshape'} _NP_EXT_OP_PREFIX = '_npx_' _NP_EXT_OP_SUBMODULE_LIST = ['_image_', '_random_'] @@ -850,12 +851,15 @@ def _init_np_op_module(root_module_name, np_module_name, mx_module_name, make_op if np_module_name == 'numpy': op_name_prefix = _NP_OP_PREFIX submodule_name_list = _NP_OP_SUBMODULE_LIST + op_implemented_set = _NP_OP_IMPLEMENTED_SET elif np_module_name == 'numpy_extension': op_name_prefix = _NP_EXT_OP_PREFIX submodule_name_list = _NP_EXT_OP_SUBMODULE_LIST + op_implemented_set = set() elif np_module_name == 'numpy._internal': op_name_prefix = _NP_INTERNAL_OP_PREFIX submodule_name_list = [] + op_implemented_set = set() else: raise ValueError('unsupported np module name {}'.format(np_module_name)) @@ -865,8 +869,12 @@ def _init_np_op_module(root_module_name, np_module_name, mx_module_name, make_op op_names = [] for i in range(size.value): name = py_str(plist[i]) - if name.startswith(op_name_prefix): - op_names.append(name) + if mx_module_name != 'symbol': + if name.startswith(op_name_prefix) and name not in op_implemented_set: + op_names.append(name) + else: + if name.startswith(op_name_prefix): + op_names.append(name) if mx_module_name is None: # register np/npx ops for imperative programming diff --git a/python/mxnet/numpy/multiarray.py b/python/mxnet/numpy/multiarray.py index 0f55c318d950..a786c74119d2 100644 --- a/python/mxnet/numpy/multiarray.py +++ b/python/mxnet/numpy/multiarray.py @@ -798,7 +798,7 @@ def __getitem__(self, key): if not unsupported: new_shape += (-4,) sliced = _npi.slice(self, begin, end, step) - return _npi.reshape(sliced, new_shape) + return _mx_nd_np.reshape(sliced, new_shape) # Special handling for cases only supported in imperative mode if dc.is_deferred_compute(): @@ -1635,9 +1635,9 @@ def reshape(self, *args, **kwargs): # pylint: disable=arguments-differ if len(args) == 0: raise TypeError('reshape() takes exactly 1 argument (0 given)') if len(args) == 1 and isinstance(args[0], tuple): - return _mx_np_op.reshape(self, newshape=args[0], order=order) + return _mx_nd_np.reshape(self, newshape=args[0], order=order) else: - return _mx_np_op.reshape(self, newshape=args, order=order) + return _mx_nd_np.reshape(self, newshape=args, order=order) def reshape_like(self, *args, **kwargs): """Convenience fluent method for :py:func:`reshape_like`. @@ -7620,7 +7620,7 @@ def mean(a, axis=None, dtype=None, out=None, keepdims=False): # pylint: disable >>> np.mean(a, dtype=np.float64) array(0.55, dtype=float64) """ - return _npi.mean(a, axis=axis, dtype=dtype, keepdims=keepdims, out=out) + return _mx_nd_np.mean(a, axis=axis, dtype=dtype, keepdims=keepdims, out=out) # pylint: enable=redefined-outer-name diff --git a/src/api/operator/numpy/np_broadcast_reduce_op_value.cc b/src/api/operator/numpy/np_broadcast_reduce_op_value.cc index 0fe7fc441209..b8f32ef65849 100644 --- a/src/api/operator/numpy/np_broadcast_reduce_op_value.cc +++ b/src/api/operator/numpy/np_broadcast_reduce_op_value.cc @@ -118,6 +118,8 @@ MXNET_REGISTER_API("_npi.mean") op::NumpyReduceAxesParam param; if (args[1].type_code() == kNull) { param.axis = dmlc::optional>(); + } else if (args[1].type_code() == kDLInt){ + param.axis = Tuple(1, args[1].operator int64_t()); } else { param.axis = mxnet::Tuple(args[1].operator ObjectRef()); } From 3b0d099f3815b38770695026c63430deca462946 Mon Sep 17 00:00:00 2001 From: barry-jin Date: Fri, 19 Mar 2021 11:42:06 -0700 Subject: [PATCH 2/9] fix sanity --- src/api/operator/numpy/np_broadcast_reduce_op_value.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/operator/numpy/np_broadcast_reduce_op_value.cc b/src/api/operator/numpy/np_broadcast_reduce_op_value.cc index b8f32ef65849..277bf4a65b42 100644 --- a/src/api/operator/numpy/np_broadcast_reduce_op_value.cc +++ b/src/api/operator/numpy/np_broadcast_reduce_op_value.cc @@ -118,7 +118,7 @@ MXNET_REGISTER_API("_npi.mean") op::NumpyReduceAxesParam param; if (args[1].type_code() == kNull) { param.axis = dmlc::optional>(); - } else if (args[1].type_code() == kDLInt){ + } else if (args[1].type_code() == kDLInt) { param.axis = Tuple(1, args[1].operator int64_t()); } else { param.axis = mxnet::Tuple(args[1].operator ObjectRef()); From be575c538e67a4ca39e6d2a1aeeb883c84bce0cb Mon Sep 17 00:00:00 2001 From: barry-jin Date: Fri, 19 Mar 2021 12:49:46 -0700 Subject: [PATCH 3/9] reshape reverse default to False --- python/mxnet/numpy/multiarray.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/mxnet/numpy/multiarray.py b/python/mxnet/numpy/multiarray.py index a786c74119d2..b2499e5efb21 100644 --- a/python/mxnet/numpy/multiarray.py +++ b/python/mxnet/numpy/multiarray.py @@ -11810,7 +11810,7 @@ def cumsum(a, axis=None, dtype=None, out=None): return _mx_nd_np.cumsum(a, axis=axis, dtype=dtype, out=out) @set_module('mxnet.numpy') -def reshape(a, newshape, reverse, order='C'): +def reshape(a, newshape, reverse=False, order='C'): """ Gives a new shape to an array without changing its data. This function always returns a copy of the input array if From 8e8ba792ae56ab78f90a2dd543d7c05ed1c17191 Mon Sep 17 00:00:00 2001 From: barry-jin Date: Fri, 19 Mar 2021 14:13:54 -0700 Subject: [PATCH 4/9] move npx.reshape to numpy_extension --- python/mxnet/ndarray/numpy/_op.py | 4 +- .../ndarray/numpy_extension/_api_internal.py | 24 ++++++ python/mxnet/ndarray/numpy_extension/_op.py | 73 ++++++++++++++++++- python/mxnet/numpy/multiarray.py | 4 +- python/mxnet/numpy_extension/_op.py | 73 ++++++++++++++++++- src/api/operator/numpy/np_matrix_op.cc | 9 +-- .../operator/numpy_extension/npx_matrix_op.cc | 57 +++++++++++++++ src/operator/numpy/np_matrix_op-inl.h | 7 ++ src/operator/numpy/np_matrix_op.cc | 2 +- 9 files changed, 241 insertions(+), 12 deletions(-) create mode 100644 python/mxnet/ndarray/numpy_extension/_api_internal.py create mode 100644 src/api/operator/numpy_extension/npx_matrix_op.cc diff --git a/python/mxnet/ndarray/numpy/_op.py b/python/mxnet/ndarray/numpy/_op.py index a1f4bcf6cc7e..c288d7331dc2 100644 --- a/python/mxnet/ndarray/numpy/_op.py +++ b/python/mxnet/ndarray/numpy/_op.py @@ -9476,7 +9476,7 @@ def cumsum(a, axis=None, dtype=None, out=None): return _api_internal.cumsum(a, axis, dtype, out) @set_module('mxnet.ndarray.numpy') -def reshape(a, newshape, reverse=False, order='C'): +def reshape(a, newshape, order='C'): """ Gives a new shape to an array without changing its data. This function always returns a copy of the input array if @@ -9537,7 +9537,7 @@ def reshape(a, newshape, reverse=False, order='C'): [3., 4.], [5., 6.]]) """ - return _api_internal.reshape(a, newshape, reverse, order) + return _api_internal.reshape(a, newshape, order) @set_module('mxnet.ndarray.numpy') def moveaxis(a, source, destination): diff --git a/python/mxnet/ndarray/numpy_extension/_api_internal.py b/python/mxnet/ndarray/numpy_extension/_api_internal.py new file mode 100644 index 000000000000..b7b2216b1f83 --- /dev/null +++ b/python/mxnet/ndarray/numpy_extension/_api_internal.py @@ -0,0 +1,24 @@ +# 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. + +"""Namespace for numpy_extension api.""" + +from ..._ffi.function import _init_api + +__all__ = [] + +_init_api("_npx", "mxnet.ndarray.numpy_extension._api_internal") diff --git a/python/mxnet/ndarray/numpy_extension/_op.py b/python/mxnet/ndarray/numpy_extension/_op.py index 22738a0f1950..7b2902e85443 100644 --- a/python/mxnet/ndarray/numpy_extension/_op.py +++ b/python/mxnet/ndarray/numpy_extension/_op.py @@ -18,4 +18,75 @@ """Namespace for the operators not belonging to the official numpy package used in Gluon dispatched by F=ndarray module.""" -__all__ = [] +from . import _api_internal +from ...util import set_module + + +__all__ = ['reshape'] + +@set_module('mxnet.ndarray.numpy_extension') +def reshape(a, newshape, reverse=False, order='C'): + """ + Gives a new shape to an array without changing its data. + This function always returns a copy of the input array if + ``out`` is not provided. + + Parameters + ---------- + a : ndarray + Array to be reshaped. + + newshape : int or tuple of ints + The new shape should be compatible with the original shape. If + an integer, then the result will be a 1-D array of that length. + One shape dimension can be -1. In this case, the value is + inferred from the length of the array and remaining dimensions. + + reverse : boolean, optional, default=0 + If true then the special values are inferred from right to left + + order : {'C'}, optional + Read the elements of `a` using this index order, and place the + elements into the reshaped array using this index order. 'C' + means to read / write the elements using C-like index order, + with the last axis index changing fastest, back to the first + axis index changing slowest. Other order types such as 'F'/'A' + may be added in the future. + + Returns + ------- + reshaped_array : ndarray + It will be always a copy of the original array. This behavior is different + from the official NumPy ``reshape`` operator where views of the original array may be + generated. + + See Also + -------- + ndarray.reshape : Equivalent method. + + Examples + -------- + >>> a = np.arange(6).reshape((3, 2)) + >>> a + array([[0., 1.], + [2., 3.], + [4., 5.]]) + + >>> np.reshape(a, (2, 3)) # C-like index ordering + array([[0., 1., 2.], + [3., 4., 5.]]) + + >>> np.reshape(np.ravel(a), (2, 3)) # equivalent to C ravel then C reshape + array([[0., 1., 2.], + [3., 4., 5.]]) + + >>> a = np.array([[1,2,3], [4,5,6]]) + >>> np.reshape(a, 6) + array([1., 2., 3., 4., 5., 6.]) + + >>> np.reshape(a, (3,-1)) # the unspecified value is inferred to be 2 + array([[1., 2.], + [3., 4.], + [5., 6.]]) + """ + return _api_internal.reshape(a, newshape, reverse, order) diff --git a/python/mxnet/numpy/multiarray.py b/python/mxnet/numpy/multiarray.py index b2499e5efb21..127dc0c44c21 100644 --- a/python/mxnet/numpy/multiarray.py +++ b/python/mxnet/numpy/multiarray.py @@ -11810,7 +11810,7 @@ def cumsum(a, axis=None, dtype=None, out=None): return _mx_nd_np.cumsum(a, axis=axis, dtype=dtype, out=out) @set_module('mxnet.numpy') -def reshape(a, newshape, reverse=False, order='C'): +def reshape(a, newshape, order='C'): """ Gives a new shape to an array without changing its data. This function always returns a copy of the input array if @@ -11871,7 +11871,7 @@ def reshape(a, newshape, reverse=False, order='C'): [3., 4.], [5., 6.]]) """ - return _mx_nd_np.reshape(a, newshape, reverse, order) + return _mx_nd_np.reshape(a, newshape, order) @set_module('mxnet.numpy') def moveaxis(a, source, destination): diff --git a/python/mxnet/numpy_extension/_op.py b/python/mxnet/numpy_extension/_op.py index a995e480221a..2bba882019ee 100644 --- a/python/mxnet/numpy_extension/_op.py +++ b/python/mxnet/numpy_extension/_op.py @@ -17,4 +17,75 @@ """Namespace for registering numpy_extension ops for imperative programming.""" -__all__ = [] +from ..ndarray import numpy_extension as _nd_npx_op +from ..util import set_module + + +__all__ = ['reshape'] + +@set_module('mxnet.numpy_extension') +def reshape(a, newshape, reverse=False, order='C'): + """ + Gives a new shape to an array without changing its data. + This function always returns a copy of the input array if + ``out`` is not provided. + + Parameters + ---------- + a : ndarray + Array to be reshaped. + + newshape : int or tuple of ints + The new shape should be compatible with the original shape. If + an integer, then the result will be a 1-D array of that length. + One shape dimension can be -1. In this case, the value is + inferred from the length of the array and remaining dimensions. + + reverse : boolean, optional, default=0 + If true then the special values are inferred from right to left + + order : {'C'}, optional + Read the elements of `a` using this index order, and place the + elements into the reshaped array using this index order. 'C' + means to read / write the elements using C-like index order, + with the last axis index changing fastest, back to the first + axis index changing slowest. Other order types such as 'F'/'A' + may be added in the future. + + Returns + ------- + reshaped_array : ndarray + It will be always a copy of the original array. This behavior is different + from the official NumPy ``reshape`` operator where views of the original array may be + generated. + + See Also + -------- + ndarray.reshape : Equivalent method. + + Examples + -------- + >>> a = np.arange(6).reshape((3, 2)) + >>> a + array([[0., 1.], + [2., 3.], + [4., 5.]]) + + >>> np.reshape(a, (2, 3)) # C-like index ordering + array([[0., 1., 2.], + [3., 4., 5.]]) + + >>> np.reshape(np.ravel(a), (2, 3)) # equivalent to C ravel then C reshape + array([[0., 1., 2.], + [3., 4., 5.]]) + + >>> a = np.array([[1,2,3], [4,5,6]]) + >>> np.reshape(a, 6) + array([1., 2., 3., 4., 5., 6.]) + + >>> np.reshape(a, (3,-1)) # the unspecified value is inferred to be 2 + array([[1., 2.], + [3., 4.], + [5., 6.]]) + """ + return _nd_npx_op.reshape(a, newshape, reverse, order) diff --git a/src/api/operator/numpy/np_matrix_op.cc b/src/api/operator/numpy/np_matrix_op.cc index 96f481db56ae..30f7f187d0f9 100644 --- a/src/api/operator/numpy/np_matrix_op.cc +++ b/src/api/operator/numpy/np_matrix_op.cc @@ -528,9 +528,9 @@ MXNET_REGISTER_API("_npi.rollaxis") MXNET_REGISTER_API("_npi.reshape") .set_body([](runtime::MXNetArgs args, runtime::MXNetRetValue* ret) { using namespace runtime; - const nnvm::Op* op = Op::Get("_npi_reshape"); + const nnvm::Op* op = Op::Get("_np_reshape"); nnvm::NodeAttrs attrs; - op::NumpyXReshapeParam param; + op::NumpyReshapeParam param; if (args[1].type_code() == kNull) { param.newshape = TShape(-1, 0); } else if (args[1].type_code() == kDLInt) { @@ -538,11 +538,10 @@ MXNET_REGISTER_API("_npi.reshape") } else { param.newshape = TShape(args[1].operator ObjectRef()); } - param.reverse = args[2].operator bool(); - param.order = args[3].operator std::string(); + param.order = args[2].operator std::string(); attrs.parsed = param; attrs.op = op; - SetAttrDict(&attrs); + SetAttrDict(&attrs); NDArray* inputs[] = {args[0].operator mxnet::NDArray*()}; int num_inputs = 1; int num_outputs = 0; diff --git a/src/api/operator/numpy_extension/npx_matrix_op.cc b/src/api/operator/numpy_extension/npx_matrix_op.cc new file mode 100644 index 000000000000..b3bf1a036e1d --- /dev/null +++ b/src/api/operator/numpy_extension/npx_matrix_op.cc @@ -0,0 +1,57 @@ +/* + * 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_matrix_op.cc + * \brief Implementation of the API of functions in src/operator/numpy/np_matrix_op.cc + */ +#include +#include +#include +#include "../utils.h" +#include "../../../operator/numpy/np_matrix_op-inl.h" + +namespace mxnet { + +MXNET_REGISTER_API("_npx.reshape") +.set_body([](runtime::MXNetArgs args, runtime::MXNetRetValue* ret) { + using namespace runtime; + const nnvm::Op* op = Op::Get("_npx_reshape"); + nnvm::NodeAttrs attrs; + op::NumpyXReshapeParam param; + if (args[1].type_code() == kNull) { + param.newshape = TShape(-1, 0); + } else if (args[1].type_code() == kDLInt) { + param.newshape = TShape(1, args[1].operator int64_t()); + } else { + param.newshape = TShape(args[1].operator ObjectRef()); + } + param.reverse = args[2].operator bool(); + param.order = args[3].operator std::string(); + attrs.parsed = 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]; +}); + +} // namespace mxnet diff --git a/src/operator/numpy/np_matrix_op-inl.h b/src/operator/numpy/np_matrix_op-inl.h index daeabc5e937a..d8eeb128e8b8 100644 --- a/src/operator/numpy/np_matrix_op-inl.h +++ b/src/operator/numpy/np_matrix_op-inl.h @@ -99,6 +99,13 @@ struct NumpyReshapeParam : public dmlc::Parameter { " Note that currently only C-like order is" " supported"); } + void SetAttrDict(std::unordered_map* dict) { + std::ostringstream newshape_s, order_s; + newshape_s << newshape; + order_s << order; + (*dict)["newshape"] = newshape_s.str(); + (*dict)["order"] = order_s.str(); + } }; struct NumpyXReshapeParam : public dmlc::Parameter { diff --git a/src/operator/numpy/np_matrix_op.cc b/src/operator/numpy/np_matrix_op.cc index 55299742878e..d7256da4a796 100644 --- a/src/operator/numpy/np_matrix_op.cc +++ b/src/operator/numpy/np_matrix_op.cc @@ -384,7 +384,7 @@ NNVM_REGISTER_OP(_np_reshape) NNVM_REGISTER_OP(_npx_reshape) .describe(R"code()code" ADD_FILELINE) -.add_alias("_npi_reshape") +.add_alias("_npx_reshape") .set_num_inputs(1) .set_num_outputs(1) .set_attr_parser(ParamParser) From c328a27699e70611aeadc14ef5843cecee1cea6b Mon Sep 17 00:00:00 2001 From: barry-jin Date: Fri, 19 Mar 2021 14:25:41 -0700 Subject: [PATCH 5/9] fix lint --- python/mxnet/ndarray/numpy_extension/_op.py | 2 +- python/mxnet/numpy_extension/_op.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python/mxnet/ndarray/numpy_extension/_op.py b/python/mxnet/ndarray/numpy_extension/_op.py index 7b2902e85443..f138bcedee95 100644 --- a/python/mxnet/ndarray/numpy_extension/_op.py +++ b/python/mxnet/ndarray/numpy_extension/_op.py @@ -41,7 +41,7 @@ def reshape(a, newshape, reverse=False, order='C'): an integer, then the result will be a 1-D array of that length. One shape dimension can be -1. In this case, the value is inferred from the length of the array and remaining dimensions. - + reverse : boolean, optional, default=0 If true then the special values are inferred from right to left diff --git a/python/mxnet/numpy_extension/_op.py b/python/mxnet/numpy_extension/_op.py index 2bba882019ee..e9c59cd79ebe 100644 --- a/python/mxnet/numpy_extension/_op.py +++ b/python/mxnet/numpy_extension/_op.py @@ -40,7 +40,7 @@ def reshape(a, newshape, reverse=False, order='C'): an integer, then the result will be a 1-D array of that length. One shape dimension can be -1. In this case, the value is inferred from the length of the array and remaining dimensions. - + reverse : boolean, optional, default=0 If true then the special values are inferred from right to left From 61e7f6bca58ca22285f5e3a86de821ffc47f906d Mon Sep 17 00:00:00 2001 From: barry-jin Date: Fri, 19 Mar 2021 16:08:25 -0700 Subject: [PATCH 6/9] use NumpyXReshapeInferShape for numpyreshapeshape --- src/operator/numpy/np_matrix_op.cc | 60 +++++++++++++++++------------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/src/operator/numpy/np_matrix_op.cc b/src/operator/numpy/np_matrix_op.cc index d7256da4a796..5b8132cdb3a4 100644 --- a/src/operator/numpy/np_matrix_op.cc +++ b/src/operator/numpy/np_matrix_op.cc @@ -174,31 +174,6 @@ bool NumpyReshapeInferShape(const mxnet::TShape& src, mxnet::TShape* dst) { } } -bool NumpyReshapeShape(const nnvm::NodeAttrs& attrs, - mxnet::ShapeVector* in_attrs, - mxnet::ShapeVector* out_attrs) { - CHECK_EQ(in_attrs->size(), 1U) << "Input: [data]"; - CHECK_EQ(out_attrs->size(), 1U); - const NumpyReshapeParam& param = nnvm::get(attrs.parsed); - // sanity check - bool has_unknown_dim_size = false; - for (int i = 0; i < param.newshape.ndim(); ++i) { - if (param.newshape[i] < 0) { - CHECK_EQ(param.newshape[i], -1) << "The shape dimension size to inferred must be -1"; - CHECK(!has_unknown_dim_size) << "Can only specify one unknown dimension"; - has_unknown_dim_size = true; - } - } - - mxnet::TShape target_shape = param.newshape; - bool success = NumpyReshapeInferShape(in_attrs->at(0), &target_shape); - SHAPE_ASSIGN_CHECK(*out_attrs, 0, target_shape); - if (!success) { - success = NumpyReshapeInferShape(out_attrs->at(0), &in_attrs->at(0)); - } - return success; -} - bool NumpyXReshapeInferShape(const mxnet::TShape& src, const mxnet::TShape& target, mxnet::TShape* output, @@ -315,6 +290,40 @@ bool NumpyXReshapeInferShape(const mxnet::TShape& src, } } +bool NumpyReshapeShape(const nnvm::NodeAttrs& attrs, + mxnet::ShapeVector* in_attrs, + mxnet::ShapeVector* out_attrs) { + CHECK_EQ(in_attrs->size(), 1U) << "Input: [data]"; + CHECK_EQ(out_attrs->size(), 1U); + const NumpyReshapeParam& param = nnvm::get(attrs.parsed); + // sanity check + bool has_unknown_dim_size = false; + for (int i = 0; i < param.newshape.ndim(); ++i) { + if (param.newshape[i] < 0) { + CHECK_GE(param.newshape[i], -6) + << "Dimension size must be greater than or equal to -6"; + if (param.newshape[i] == -1) { + CHECK(!has_unknown_dim_size) << "Can only specify one unknown dimension"; + has_unknown_dim_size = true; + } + } + } + + mxnet::TShape output_shape; + std::stringstream ss; + ss << "Cannot reshape array of shape " << in_attrs->at(0) + << " into shape " << param.newshape; + std::string err_msg = ss.str(); + mxnet::TShape target_shape = param.newshape; + bool success = NumpyXReshapeInferShape(in_attrs->at(0), + target_shape, &output_shape, err_msg); + SHAPE_ASSIGN_CHECK(*out_attrs, 0, output_shape); + if (!success) { + success = NumpyReshapeInferShape(out_attrs->at(0), &in_attrs->at(0)); + } + return success; +} + bool NumpyXReshapeShape(const nnvm::NodeAttrs& attrs, mxnet::ShapeVector* in_attrs, mxnet::ShapeVector* out_attrs) { @@ -385,6 +394,7 @@ NNVM_REGISTER_OP(_np_reshape) NNVM_REGISTER_OP(_npx_reshape) .describe(R"code()code" ADD_FILELINE) .add_alias("_npx_reshape") +.add_alias("_npi_reshape") .set_num_inputs(1) .set_num_outputs(1) .set_attr_parser(ParamParser) From ab405c2546c89f7c7d87496a4838c53a02d06e76 Mon Sep 17 00:00:00 2001 From: barry-jin Date: Fri, 19 Mar 2021 19:20:09 -0700 Subject: [PATCH 7/9] Revert "use NumpyXReshapeInferShape for numpyreshapeshape" This reverts commit 61e7f6bca58ca22285f5e3a86de821ffc47f906d. --- src/operator/numpy/np_matrix_op.cc | 60 +++++++++++++----------------- 1 file changed, 25 insertions(+), 35 deletions(-) diff --git a/src/operator/numpy/np_matrix_op.cc b/src/operator/numpy/np_matrix_op.cc index 5b8132cdb3a4..d7256da4a796 100644 --- a/src/operator/numpy/np_matrix_op.cc +++ b/src/operator/numpy/np_matrix_op.cc @@ -174,6 +174,31 @@ bool NumpyReshapeInferShape(const mxnet::TShape& src, mxnet::TShape* dst) { } } +bool NumpyReshapeShape(const nnvm::NodeAttrs& attrs, + mxnet::ShapeVector* in_attrs, + mxnet::ShapeVector* out_attrs) { + CHECK_EQ(in_attrs->size(), 1U) << "Input: [data]"; + CHECK_EQ(out_attrs->size(), 1U); + const NumpyReshapeParam& param = nnvm::get(attrs.parsed); + // sanity check + bool has_unknown_dim_size = false; + for (int i = 0; i < param.newshape.ndim(); ++i) { + if (param.newshape[i] < 0) { + CHECK_EQ(param.newshape[i], -1) << "The shape dimension size to inferred must be -1"; + CHECK(!has_unknown_dim_size) << "Can only specify one unknown dimension"; + has_unknown_dim_size = true; + } + } + + mxnet::TShape target_shape = param.newshape; + bool success = NumpyReshapeInferShape(in_attrs->at(0), &target_shape); + SHAPE_ASSIGN_CHECK(*out_attrs, 0, target_shape); + if (!success) { + success = NumpyReshapeInferShape(out_attrs->at(0), &in_attrs->at(0)); + } + return success; +} + bool NumpyXReshapeInferShape(const mxnet::TShape& src, const mxnet::TShape& target, mxnet::TShape* output, @@ -290,40 +315,6 @@ bool NumpyXReshapeInferShape(const mxnet::TShape& src, } } -bool NumpyReshapeShape(const nnvm::NodeAttrs& attrs, - mxnet::ShapeVector* in_attrs, - mxnet::ShapeVector* out_attrs) { - CHECK_EQ(in_attrs->size(), 1U) << "Input: [data]"; - CHECK_EQ(out_attrs->size(), 1U); - const NumpyReshapeParam& param = nnvm::get(attrs.parsed); - // sanity check - bool has_unknown_dim_size = false; - for (int i = 0; i < param.newshape.ndim(); ++i) { - if (param.newshape[i] < 0) { - CHECK_GE(param.newshape[i], -6) - << "Dimension size must be greater than or equal to -6"; - if (param.newshape[i] == -1) { - CHECK(!has_unknown_dim_size) << "Can only specify one unknown dimension"; - has_unknown_dim_size = true; - } - } - } - - mxnet::TShape output_shape; - std::stringstream ss; - ss << "Cannot reshape array of shape " << in_attrs->at(0) - << " into shape " << param.newshape; - std::string err_msg = ss.str(); - mxnet::TShape target_shape = param.newshape; - bool success = NumpyXReshapeInferShape(in_attrs->at(0), - target_shape, &output_shape, err_msg); - SHAPE_ASSIGN_CHECK(*out_attrs, 0, output_shape); - if (!success) { - success = NumpyReshapeInferShape(out_attrs->at(0), &in_attrs->at(0)); - } - return success; -} - bool NumpyXReshapeShape(const nnvm::NodeAttrs& attrs, mxnet::ShapeVector* in_attrs, mxnet::ShapeVector* out_attrs) { @@ -394,7 +385,6 @@ NNVM_REGISTER_OP(_np_reshape) NNVM_REGISTER_OP(_npx_reshape) .describe(R"code()code" ADD_FILELINE) .add_alias("_npx_reshape") -.add_alias("_npi_reshape") .set_num_inputs(1) .set_num_outputs(1) .set_attr_parser(ParamParser) From 16d5d3b21d625cfffea8613d4474dde4f93148e9 Mon Sep 17 00:00:00 2001 From: barry-jin Date: Fri, 19 Mar 2021 19:33:28 -0700 Subject: [PATCH 8/9] revert --- .../ndarray/numpy_extension/_api_internal.py | 24 ------ python/mxnet/ndarray/numpy_extension/_op.py | 73 +------------------ python/mxnet/numpy_extension/_op.py | 73 +------------------ src/api/operator/numpy/np_matrix_op.cc | 9 ++- .../operator/numpy_extension/npx_matrix_op.cc | 57 --------------- src/operator/numpy/np_matrix_op-inl.h | 7 -- src/operator/numpy/np_matrix_op.cc | 2 +- 7 files changed, 8 insertions(+), 237 deletions(-) delete mode 100644 python/mxnet/ndarray/numpy_extension/_api_internal.py delete mode 100644 src/api/operator/numpy_extension/npx_matrix_op.cc diff --git a/python/mxnet/ndarray/numpy_extension/_api_internal.py b/python/mxnet/ndarray/numpy_extension/_api_internal.py deleted file mode 100644 index b7b2216b1f83..000000000000 --- a/python/mxnet/ndarray/numpy_extension/_api_internal.py +++ /dev/null @@ -1,24 +0,0 @@ -# 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. - -"""Namespace for numpy_extension api.""" - -from ..._ffi.function import _init_api - -__all__ = [] - -_init_api("_npx", "mxnet.ndarray.numpy_extension._api_internal") diff --git a/python/mxnet/ndarray/numpy_extension/_op.py b/python/mxnet/ndarray/numpy_extension/_op.py index f138bcedee95..22738a0f1950 100644 --- a/python/mxnet/ndarray/numpy_extension/_op.py +++ b/python/mxnet/ndarray/numpy_extension/_op.py @@ -18,75 +18,4 @@ """Namespace for the operators not belonging to the official numpy package used in Gluon dispatched by F=ndarray module.""" -from . import _api_internal -from ...util import set_module - - -__all__ = ['reshape'] - -@set_module('mxnet.ndarray.numpy_extension') -def reshape(a, newshape, reverse=False, order='C'): - """ - Gives a new shape to an array without changing its data. - This function always returns a copy of the input array if - ``out`` is not provided. - - Parameters - ---------- - a : ndarray - Array to be reshaped. - - newshape : int or tuple of ints - The new shape should be compatible with the original shape. If - an integer, then the result will be a 1-D array of that length. - One shape dimension can be -1. In this case, the value is - inferred from the length of the array and remaining dimensions. - - reverse : boolean, optional, default=0 - If true then the special values are inferred from right to left - - order : {'C'}, optional - Read the elements of `a` using this index order, and place the - elements into the reshaped array using this index order. 'C' - means to read / write the elements using C-like index order, - with the last axis index changing fastest, back to the first - axis index changing slowest. Other order types such as 'F'/'A' - may be added in the future. - - Returns - ------- - reshaped_array : ndarray - It will be always a copy of the original array. This behavior is different - from the official NumPy ``reshape`` operator where views of the original array may be - generated. - - See Also - -------- - ndarray.reshape : Equivalent method. - - Examples - -------- - >>> a = np.arange(6).reshape((3, 2)) - >>> a - array([[0., 1.], - [2., 3.], - [4., 5.]]) - - >>> np.reshape(a, (2, 3)) # C-like index ordering - array([[0., 1., 2.], - [3., 4., 5.]]) - - >>> np.reshape(np.ravel(a), (2, 3)) # equivalent to C ravel then C reshape - array([[0., 1., 2.], - [3., 4., 5.]]) - - >>> a = np.array([[1,2,3], [4,5,6]]) - >>> np.reshape(a, 6) - array([1., 2., 3., 4., 5., 6.]) - - >>> np.reshape(a, (3,-1)) # the unspecified value is inferred to be 2 - array([[1., 2.], - [3., 4.], - [5., 6.]]) - """ - return _api_internal.reshape(a, newshape, reverse, order) +__all__ = [] diff --git a/python/mxnet/numpy_extension/_op.py b/python/mxnet/numpy_extension/_op.py index e9c59cd79ebe..a995e480221a 100644 --- a/python/mxnet/numpy_extension/_op.py +++ b/python/mxnet/numpy_extension/_op.py @@ -17,75 +17,4 @@ """Namespace for registering numpy_extension ops for imperative programming.""" -from ..ndarray import numpy_extension as _nd_npx_op -from ..util import set_module - - -__all__ = ['reshape'] - -@set_module('mxnet.numpy_extension') -def reshape(a, newshape, reverse=False, order='C'): - """ - Gives a new shape to an array without changing its data. - This function always returns a copy of the input array if - ``out`` is not provided. - - Parameters - ---------- - a : ndarray - Array to be reshaped. - - newshape : int or tuple of ints - The new shape should be compatible with the original shape. If - an integer, then the result will be a 1-D array of that length. - One shape dimension can be -1. In this case, the value is - inferred from the length of the array and remaining dimensions. - - reverse : boolean, optional, default=0 - If true then the special values are inferred from right to left - - order : {'C'}, optional - Read the elements of `a` using this index order, and place the - elements into the reshaped array using this index order. 'C' - means to read / write the elements using C-like index order, - with the last axis index changing fastest, back to the first - axis index changing slowest. Other order types such as 'F'/'A' - may be added in the future. - - Returns - ------- - reshaped_array : ndarray - It will be always a copy of the original array. This behavior is different - from the official NumPy ``reshape`` operator where views of the original array may be - generated. - - See Also - -------- - ndarray.reshape : Equivalent method. - - Examples - -------- - >>> a = np.arange(6).reshape((3, 2)) - >>> a - array([[0., 1.], - [2., 3.], - [4., 5.]]) - - >>> np.reshape(a, (2, 3)) # C-like index ordering - array([[0., 1., 2.], - [3., 4., 5.]]) - - >>> np.reshape(np.ravel(a), (2, 3)) # equivalent to C ravel then C reshape - array([[0., 1., 2.], - [3., 4., 5.]]) - - >>> a = np.array([[1,2,3], [4,5,6]]) - >>> np.reshape(a, 6) - array([1., 2., 3., 4., 5., 6.]) - - >>> np.reshape(a, (3,-1)) # the unspecified value is inferred to be 2 - array([[1., 2.], - [3., 4.], - [5., 6.]]) - """ - return _nd_npx_op.reshape(a, newshape, reverse, order) +__all__ = [] diff --git a/src/api/operator/numpy/np_matrix_op.cc b/src/api/operator/numpy/np_matrix_op.cc index 30f7f187d0f9..96f481db56ae 100644 --- a/src/api/operator/numpy/np_matrix_op.cc +++ b/src/api/operator/numpy/np_matrix_op.cc @@ -528,9 +528,9 @@ MXNET_REGISTER_API("_npi.rollaxis") MXNET_REGISTER_API("_npi.reshape") .set_body([](runtime::MXNetArgs args, runtime::MXNetRetValue* ret) { using namespace runtime; - const nnvm::Op* op = Op::Get("_np_reshape"); + const nnvm::Op* op = Op::Get("_npi_reshape"); nnvm::NodeAttrs attrs; - op::NumpyReshapeParam param; + op::NumpyXReshapeParam param; if (args[1].type_code() == kNull) { param.newshape = TShape(-1, 0); } else if (args[1].type_code() == kDLInt) { @@ -538,10 +538,11 @@ MXNET_REGISTER_API("_npi.reshape") } else { param.newshape = TShape(args[1].operator ObjectRef()); } - param.order = args[2].operator std::string(); + param.reverse = args[2].operator bool(); + param.order = args[3].operator std::string(); attrs.parsed = param; attrs.op = op; - SetAttrDict(&attrs); + SetAttrDict(&attrs); NDArray* inputs[] = {args[0].operator mxnet::NDArray*()}; int num_inputs = 1; int num_outputs = 0; diff --git a/src/api/operator/numpy_extension/npx_matrix_op.cc b/src/api/operator/numpy_extension/npx_matrix_op.cc deleted file mode 100644 index b3bf1a036e1d..000000000000 --- a/src/api/operator/numpy_extension/npx_matrix_op.cc +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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_matrix_op.cc - * \brief Implementation of the API of functions in src/operator/numpy/np_matrix_op.cc - */ -#include -#include -#include -#include "../utils.h" -#include "../../../operator/numpy/np_matrix_op-inl.h" - -namespace mxnet { - -MXNET_REGISTER_API("_npx.reshape") -.set_body([](runtime::MXNetArgs args, runtime::MXNetRetValue* ret) { - using namespace runtime; - const nnvm::Op* op = Op::Get("_npx_reshape"); - nnvm::NodeAttrs attrs; - op::NumpyXReshapeParam param; - if (args[1].type_code() == kNull) { - param.newshape = TShape(-1, 0); - } else if (args[1].type_code() == kDLInt) { - param.newshape = TShape(1, args[1].operator int64_t()); - } else { - param.newshape = TShape(args[1].operator ObjectRef()); - } - param.reverse = args[2].operator bool(); - param.order = args[3].operator std::string(); - attrs.parsed = 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]; -}); - -} // namespace mxnet diff --git a/src/operator/numpy/np_matrix_op-inl.h b/src/operator/numpy/np_matrix_op-inl.h index d8eeb128e8b8..daeabc5e937a 100644 --- a/src/operator/numpy/np_matrix_op-inl.h +++ b/src/operator/numpy/np_matrix_op-inl.h @@ -99,13 +99,6 @@ struct NumpyReshapeParam : public dmlc::Parameter { " Note that currently only C-like order is" " supported"); } - void SetAttrDict(std::unordered_map* dict) { - std::ostringstream newshape_s, order_s; - newshape_s << newshape; - order_s << order; - (*dict)["newshape"] = newshape_s.str(); - (*dict)["order"] = order_s.str(); - } }; struct NumpyXReshapeParam : public dmlc::Parameter { diff --git a/src/operator/numpy/np_matrix_op.cc b/src/operator/numpy/np_matrix_op.cc index d7256da4a796..55299742878e 100644 --- a/src/operator/numpy/np_matrix_op.cc +++ b/src/operator/numpy/np_matrix_op.cc @@ -384,7 +384,7 @@ NNVM_REGISTER_OP(_np_reshape) NNVM_REGISTER_OP(_npx_reshape) .describe(R"code()code" ADD_FILELINE) -.add_alias("_npx_reshape") +.add_alias("_npi_reshape") .set_num_inputs(1) .set_num_outputs(1) .set_attr_parser(ParamParser) From 78453a2082b66173ba7f38c96cd8b6785bfa9ef4 Mon Sep 17 00:00:00 2001 From: barry-jin Date: Fri, 19 Mar 2021 21:42:02 -0700 Subject: [PATCH 9/9] update --- python/mxnet/ndarray/numpy/_op.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/mxnet/ndarray/numpy/_op.py b/python/mxnet/ndarray/numpy/_op.py index c288d7331dc2..ff0dbdeb3703 100644 --- a/python/mxnet/ndarray/numpy/_op.py +++ b/python/mxnet/ndarray/numpy/_op.py @@ -9537,7 +9537,7 @@ def reshape(a, newshape, order='C'): [3., 4.], [5., 6.]]) """ - return _api_internal.reshape(a, newshape, order) + return _api_internal.reshape(a, newshape, False, order) @set_module('mxnet.ndarray.numpy') def moveaxis(a, source, destination):