From f8f206da94f7175193a243b517ff5dda60f4a923 Mon Sep 17 00:00:00 2001 From: AntiZpvoh Date: Mon, 16 Mar 2020 14:15:17 +0000 Subject: [PATCH 1/3] add random.shuffle, equal, not_equal, less_equal, greater_equal, less, maximum and minimum ffi and benchmark --- benchmark/python/ffi/benchmark_ffi.py | 8 +++ python/mxnet/ndarray/numpy/_op.py | 32 ++++++--- python/mxnet/ndarray/numpy/random.py | 2 +- .../numpy/np_elemwise_broadcast_logic_op.cc | 71 +++++++++++++++++++ src/api/operator/random/shuffle_op.cc | 58 +++++++++++++++ .../elemwise_binary_broadcast_op_extended.cc | 47 ++++++++++++ 6 files changed, 208 insertions(+), 10 deletions(-) create mode 100644 src/api/operator/numpy/np_elemwise_broadcast_logic_op.cc create mode 100644 src/api/operator/random/shuffle_op.cc create mode 100644 src/api/operator/tensor/elemwise_binary_broadcast_op_extended.cc diff --git a/benchmark/python/ffi/benchmark_ffi.py b/benchmark/python/ffi/benchmark_ffi.py index 88af3cf3d55e..538bd48ec021 100644 --- a/benchmark/python/ffi/benchmark_ffi.py +++ b/benchmark/python/ffi/benchmark_ffi.py @@ -53,6 +53,14 @@ def prepare_workloads(): OpArgMngr.add_workload("zeros", (2, 2)) OpArgMngr.add_workload("tensordot", pool['2x2'], pool['2x2'], ((1, 0), (0, 1))) OpArgMngr.add_workload("cumsum", pool['3x2'], axis=0, out=pool['3x2']) + OpArgMngr.add_workload("random.shuffle", pool['3']) + OpArgMngr.add_workload("equal", pool['2x2'], pool['2x2']) + OpArgMngr.add_workload("not_equal", pool['2x2'], pool['2x2']) + OpArgMngr.add_workload("less", pool['2x2'], pool['2x2']) + OpArgMngr.add_workload("greater_equal", pool['2x2'], pool['2x2']) + OpArgMngr.add_workload("less_equal", pool['2x2'], pool['2x2']) + OpArgMngr.add_workload("maximum", pool['2x2'], pool['2x2']) + OpArgMngr.add_workload("minimum", pool['2x2'], pool['2x2']) OpArgMngr.add_workload("add", pool['2x2'], pool['2x2']) OpArgMngr.add_workload("random.uniform", low=0, high=1, size=1) diff --git a/python/mxnet/ndarray/numpy/_op.py b/python/mxnet/ndarray/numpy/_op.py index 3d30333d6da2..bba4878f05fe 100644 --- a/python/mxnet/ndarray/numpy/_op.py +++ b/python/mxnet/ndarray/numpy/_op.py @@ -4364,7 +4364,9 @@ def maximum(x1, x2, out=None, **kwargs): ------- out : mxnet.numpy.ndarray or scalar The maximum of x1 and x2, element-wise. This is a scalar if both x1 and x2 are scalars.""" - return _ufunc_helper(x1, x2, _npi.maximum, _np.maximum, _npi.maximum_scalar, None, out) + if isinstance(x1, numeric_types) and isinstance(x2, numeric_types): + _np.maximum(x1, x2, out=out) + return _api_internal.maximum(x1, x2, out) @set_module('mxnet.ndarray.numpy') @@ -4383,7 +4385,9 @@ def minimum(x1, x2, out=None, **kwargs): ------- out : mxnet.numpy.ndarray or scalar The minimum of x1 and x2, element-wise. This is a scalar if both x1 and x2 are scalars.""" - return _ufunc_helper(x1, x2, _npi.minimum, _np.minimum, _npi.minimum_scalar, None, out) + if isinstance(x1, numeric_types) and isinstance(x2, numeric_types): + _np.minimum(x1, x2, out=out) + return _api_internal.minimum(x1, x2, out) @set_module('mxnet.ndarray.numpy') @@ -6142,7 +6146,9 @@ def equal(x1, x2, out=None): >>> np.equal(1, np.ones(1)) array([ True]) """ - return _ufunc_helper(x1, x2, _npi.equal, _np.equal, _npi.equal_scalar, None, out) + if isinstance(x1, numeric_types) and isinstance(x2, numeric_types): + _np.equal(x1, x2, out=out) + return _api_internal.equal(x1, x2, out) @set_module('mxnet.ndarray.numpy') @@ -6174,7 +6180,10 @@ def not_equal(x1, x2, out=None): >>> np.not_equal(1, np.ones(1)) array([False]) """ - return _ufunc_helper(x1, x2, _npi.not_equal, _np.not_equal, _npi.not_equal_scalar, None, out) + if isinstance(x1, numeric_types) and isinstance(x2, numeric_types): + _np.not_equal(x1, x2, out=out) + return _api_internal.not_equal(x1, x2, out) + @set_module('mxnet.ndarray.numpy') @@ -6239,7 +6248,9 @@ def less(x1, x2, out=None): >>> np.less(1, np.ones(1)) array([False]) """ - return _ufunc_helper(x1, x2, _npi.less, _np.less, _npi.less_scalar, _npi.greater_scalar, out) + if isinstance(x1, numeric_types) and isinstance(x2, numeric_types): + _np.less(x1, x2, out=out) + return _api_internal.less(x1, x2, out) @set_module('mxnet.ndarray.numpy') @@ -6271,8 +6282,10 @@ def greater_equal(x1, x2, out=None): >>> np.greater_equal(1, np.ones(1)) array([True]) """ - return _ufunc_helper(x1, x2, _npi.greater_equal, _np.greater_equal, _npi.greater_equal_scalar, - _npi.less_equal_scalar, out) + if isinstance(x1, numeric_types) and isinstance(x2, numeric_types): + _np.greater_equal(x1, x2, out=out) + return _api_internal.greater_equal(x1, x2, out) + @set_module('mxnet.ndarray.numpy') @@ -6304,8 +6317,9 @@ def less_equal(x1, x2, out=None): >>> np.less_equal(1, np.ones(1)) array([True]) """ - return _ufunc_helper(x1, x2, _npi.less_equal, _np.less_equal, _npi.less_equal_scalar, - _npi.greater_equal_scalar, out) + if isinstance(x1, numeric_types) and isinstance(x2, numeric_types): + _np.less_equal(x1, x2, out=out) + return _api_internal.less_equal(x1, x2, out) @set_module('mxnet.ndarray.numpy') diff --git a/python/mxnet/ndarray/numpy/random.py b/python/mxnet/ndarray/numpy/random.py index 616aafc7c524..d8f165336e36 100644 --- a/python/mxnet/ndarray/numpy/random.py +++ b/python/mxnet/ndarray/numpy/random.py @@ -1068,7 +1068,7 @@ def shuffle(x): [3., 4., 5.], [0., 1., 2.]]) """ - _npi.shuffle(x, out=x) + _api_internal.shuffle(x, x) def laplace(loc=0.0, scale=1.0, size=None, dtype=None, ctx=None, out=None): diff --git a/src/api/operator/numpy/np_elemwise_broadcast_logic_op.cc b/src/api/operator/numpy/np_elemwise_broadcast_logic_op.cc new file mode 100644 index 000000000000..7bde443dad9e --- /dev/null +++ b/src/api/operator/numpy/np_elemwise_broadcast_logic_op.cc @@ -0,0 +1,71 @@ +/* + * 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_elemwise_broadcast_logic_op.cc + * \brief Implementation of the API of functions in src/operator/numpy/np_elemwise_broadcast_logic_op.cc + */ +#include +#include +#include "../utils.h" +#include "../ufunc_helper.h" + +namespace mxnet { + +MXNET_REGISTER_API("_npi.equal") +.set_body([](runtime::MXNetArgs args, runtime::MXNetRetValue* ret) { + using namespace runtime; + const nnvm::Op* op = Op::Get("_npi_equal"); + const nnvm::Op* op_scalar = Op::Get("_npi_equal_scalar"); + UFuncHelper(args, ret, op, op_scalar, nullptr); +}); + +MXNET_REGISTER_API("_npi.not_equal") +.set_body([](runtime::MXNetArgs args, runtime::MXNetRetValue* ret) { + using namespace runtime; + const nnvm::Op* op = Op::Get("_npi_not_equal"); + const nnvm::Op* op_scalar = Op::Get("_npi_not_equal_scalar"); + UFuncHelper(args, ret, op, op_scalar, nullptr); +}); + +MXNET_REGISTER_API("_npi.less") +.set_body([](runtime::MXNetArgs args, runtime::MXNetRetValue* ret) { + using namespace runtime; + const nnvm::Op* op = Op::Get("_npi_less"); + const nnvm::Op* op_scalar = Op::Get("_npi_less_scalar"); + UFuncHelper(args, ret, op, op_scalar, nullptr); +}); + +MXNET_REGISTER_API("_npi.greater_equal") +.set_body([](runtime::MXNetArgs args, runtime::MXNetRetValue* ret) { + using namespace runtime; + const nnvm::Op* op = Op::Get("_npi_greater_equal"); + const nnvm::Op* op_scalar = Op::Get("_npi_greater_equal_scalar"); + UFuncHelper(args, ret, op, op_scalar, nullptr); +}); + +MXNET_REGISTER_API("_npi.less_equal") +.set_body([](runtime::MXNetArgs args, runtime::MXNetRetValue* ret) { + using namespace runtime; + const nnvm::Op* op = Op::Get("_npi_less_equal"); + const nnvm::Op* op_scalar = Op::Get("_npi_less_equal_scalar"); + UFuncHelper(args, ret, op, op_scalar, nullptr); +}); + +} // namespace mxnet diff --git a/src/api/operator/random/shuffle_op.cc b/src/api/operator/random/shuffle_op.cc new file mode 100644 index 000000000000..e309acc2cb2e --- /dev/null +++ b/src/api/operator/random/shuffle_op.cc @@ -0,0 +1,58 @@ +/* + * 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 shuffle_op.cc + * \brief Implementation of the API of functions in src/operator/random/shuffle_op.cc + */ +#include +#include +#include "../utils.h" +#include "../../../operator/elemwise_op_common.h" + +namespace mxnet { + +MXNET_REGISTER_API("_npi.shuffle") +.set_body([](runtime::MXNetArgs args, runtime::MXNetRetValue* ret) { + using namespace runtime; + const nnvm::Op* op = Op::Get("_npi_shuffle"); + nnvm::NodeAttrs attrs; + + NDArray** inputs = new NDArray*[1](); + int num_inputs = 1; + + if (args[0].type_code() != kNull) { + inputs[0] = args[0].operator mxnet::NDArray *(); + } + + attrs.op = op; + inputs = inputs == nullptr ? nullptr : inputs; + + NDArray* out = args[1].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(1); + } else { + *ret = ndoutputs[0]; + } +}); + +} // namespace mxnet diff --git a/src/api/operator/tensor/elemwise_binary_broadcast_op_extended.cc b/src/api/operator/tensor/elemwise_binary_broadcast_op_extended.cc new file mode 100644 index 000000000000..f25e30a8b081 --- /dev/null +++ b/src/api/operator/tensor/elemwise_binary_broadcast_op_extended.cc @@ -0,0 +1,47 @@ +/* + * 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 elemwise_binary_broadcast_op_extended.cc + * \brief Implementation of the API of functions in src/operator/tensor/elemwise_binary_broadcast_op_extended.cc + */ +#include +#include +#include "../utils.h" +#include "../ufunc_helper.h" + +namespace mxnet { + +MXNET_REGISTER_API("_npi.maximum") +.set_body([](runtime::MXNetArgs args, runtime::MXNetRetValue* ret) { + using namespace runtime; + const nnvm::Op* op = Op::Get("_npi_maximum"); + const nnvm::Op* op_scalar = Op::Get("_npi_maximum_scalar"); + UFuncHelper(args, ret, op, op_scalar, nullptr); +}); + +MXNET_REGISTER_API("_npi.minimum") +.set_body([](runtime::MXNetArgs args, runtime::MXNetRetValue* ret) { + using namespace runtime; + const nnvm::Op* op = Op::Get("_npi_minimum"); + const nnvm::Op* op_scalar = Op::Get("_npi_minimum_scalar"); + UFuncHelper(args, ret, op, op_scalar, nullptr); +}); + +} // namespace mxnet From 757e6a49910481f90e63cd9befd88f6e93016ef8 Mon Sep 17 00:00:00 2001 From: AntiZpvoh Date: Tue, 24 Mar 2020 06:08:48 +0000 Subject: [PATCH 2/3] fix the implementation of binary ops --- python/mxnet/ndarray/numpy/_op.py | 14 +++++++------- src/api/operator/random/shuffle_op.cc | 3 +-- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/python/mxnet/ndarray/numpy/_op.py b/python/mxnet/ndarray/numpy/_op.py index 1d25a7b66410..7b559221c7b1 100644 --- a/python/mxnet/ndarray/numpy/_op.py +++ b/python/mxnet/ndarray/numpy/_op.py @@ -4364,7 +4364,7 @@ def maximum(x1, x2, out=None, **kwargs): out : mxnet.numpy.ndarray or scalar The maximum of x1 and x2, element-wise. This is a scalar if both x1 and x2 are scalars.""" if isinstance(x1, numeric_types) and isinstance(x2, numeric_types): - _np.maximum(x1, x2, out=out) + return _np.maximum(x1, x2, out=out) return _api_internal.maximum(x1, x2, out) @@ -4385,7 +4385,7 @@ def minimum(x1, x2, out=None, **kwargs): out : mxnet.numpy.ndarray or scalar The minimum of x1 and x2, element-wise. This is a scalar if both x1 and x2 are scalars.""" if isinstance(x1, numeric_types) and isinstance(x2, numeric_types): - _np.minimum(x1, x2, out=out) + return _np.minimum(x1, x2, out=out) return _api_internal.minimum(x1, x2, out) @@ -6148,7 +6148,7 @@ def equal(x1, x2, out=None): array([ True]) """ if isinstance(x1, numeric_types) and isinstance(x2, numeric_types): - _np.equal(x1, x2, out=out) + return _np.equal(x1, x2, out=out) return _api_internal.equal(x1, x2, out) @@ -6182,7 +6182,7 @@ def not_equal(x1, x2, out=None): array([False]) """ if isinstance(x1, numeric_types) and isinstance(x2, numeric_types): - _np.not_equal(x1, x2, out=out) + return _np.not_equal(x1, x2, out=out) return _api_internal.not_equal(x1, x2, out) @@ -6250,7 +6250,7 @@ def less(x1, x2, out=None): array([False]) """ if isinstance(x1, numeric_types) and isinstance(x2, numeric_types): - _np.less(x1, x2, out=out) + return _np.less(x1, x2, out=out) return _api_internal.less(x1, x2, out) @@ -6284,7 +6284,7 @@ def greater_equal(x1, x2, out=None): array([True]) """ if isinstance(x1, numeric_types) and isinstance(x2, numeric_types): - _np.greater_equal(x1, x2, out=out) + return _np.greater_equal(x1, x2, out=out) return _api_internal.greater_equal(x1, x2, out) @@ -6319,7 +6319,7 @@ def less_equal(x1, x2, out=None): array([True]) """ if isinstance(x1, numeric_types) and isinstance(x2, numeric_types): - _np.less_equal(x1, x2, out=out) + return _np.less_equal(x1, x2, out=out) return _api_internal.less_equal(x1, x2, out) diff --git a/src/api/operator/random/shuffle_op.cc b/src/api/operator/random/shuffle_op.cc index e309acc2cb2e..222451cb0f3b 100644 --- a/src/api/operator/random/shuffle_op.cc +++ b/src/api/operator/random/shuffle_op.cc @@ -34,7 +34,7 @@ MXNET_REGISTER_API("_npi.shuffle") const nnvm::Op* op = Op::Get("_npi_shuffle"); nnvm::NodeAttrs attrs; - NDArray** inputs = new NDArray*[1](); + NDArray* inputs[1]; int num_inputs = 1; if (args[0].type_code() != kNull) { @@ -42,7 +42,6 @@ MXNET_REGISTER_API("_npi.shuffle") } attrs.op = op; - inputs = inputs == nullptr ? nullptr : inputs; NDArray* out = args[1].operator mxnet::NDArray*(); NDArray** outputs = out == nullptr ? nullptr : &out; From afc4aaacfd6684a688f6cb420db38cb2c4a3d048 Mon Sep 17 00:00:00 2001 From: AntiZpvoh Date: Wed, 25 Mar 2020 06:52:54 +0000 Subject: [PATCH 3/3] fix some code logic issues (non-commutative) --- src/api/operator/numpy/np_elemwise_broadcast_logic_op.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/api/operator/numpy/np_elemwise_broadcast_logic_op.cc b/src/api/operator/numpy/np_elemwise_broadcast_logic_op.cc index 7bde443dad9e..f0ca4081b2c8 100644 --- a/src/api/operator/numpy/np_elemwise_broadcast_logic_op.cc +++ b/src/api/operator/numpy/np_elemwise_broadcast_logic_op.cc @@ -49,7 +49,8 @@ MXNET_REGISTER_API("_npi.less") using namespace runtime; const nnvm::Op* op = Op::Get("_npi_less"); const nnvm::Op* op_scalar = Op::Get("_npi_less_scalar"); - UFuncHelper(args, ret, op, op_scalar, nullptr); + const nnvm::Op* op_rscalar = Op::Get("_npi_less_scalar"); + UFuncHelper(args, ret, op, op_scalar, op_rscalar); }); MXNET_REGISTER_API("_npi.greater_equal") @@ -57,7 +58,8 @@ MXNET_REGISTER_API("_npi.greater_equal") using namespace runtime; const nnvm::Op* op = Op::Get("_npi_greater_equal"); const nnvm::Op* op_scalar = Op::Get("_npi_greater_equal_scalar"); - UFuncHelper(args, ret, op, op_scalar, nullptr); + const nnvm::Op* op_rscalar = Op::Get("_npi_greater_equal_scalar"); + UFuncHelper(args, ret, op, op_scalar, op_rscalar); }); MXNET_REGISTER_API("_npi.less_equal") @@ -65,7 +67,8 @@ MXNET_REGISTER_API("_npi.less_equal") using namespace runtime; const nnvm::Op* op = Op::Get("_npi_less_equal"); const nnvm::Op* op_scalar = Op::Get("_npi_less_equal_scalar"); - UFuncHelper(args, ret, op, op_scalar, nullptr); + const nnvm::Op* op_rscalar = Op::Get("_npi_less_equal_scalar"); + UFuncHelper(args, ret, op, op_scalar, op_rscalar); }); } // namespace mxnet