From 585b238b9b7f7bb150a5a85e8e6d02b40d228cf8 Mon Sep 17 00:00:00 2001 From: AntiZpvoh Date: Wed, 15 Jan 2020 01:01:49 +0800 Subject: [PATCH 01/22] NumPy Laplace Distribution partly Frontend and Backend Signed-off-by: AntiZpvoh --- python/mxnet/ndarray/numpy/random.py | 51 ++++- python/mxnet/numpy/random.py | 29 +++ src/operator/numpy/random/np_laplace_op.cc | 105 ++++++++++ src/operator/numpy/random/np_laplace_op.cu | 35 ++++ src/operator/numpy/random/np_laplace_op.h | 219 +++++++++++++++++++++ 5 files changed, 438 insertions(+), 1 deletion(-) create mode 100644 src/operator/numpy/random/np_laplace_op.cc create mode 100644 src/operator/numpy/random/np_laplace_op.cu create mode 100644 src/operator/numpy/random/np_laplace_op.h diff --git a/python/mxnet/ndarray/numpy/random.py b/python/mxnet/ndarray/numpy/random.py index 913ceaaff097..4eabee11117c 100644 --- a/python/mxnet/ndarray/numpy/random.py +++ b/python/mxnet/ndarray/numpy/random.py @@ -23,7 +23,7 @@ from ..ndarray import NDArray -__all__ = ['randint', 'uniform', 'normal', "choice", "rand", "multinomial", "shuffle", 'gamma'] +__all__ = ['randint', 'uniform', 'normal', "choice", "rand", "multinomial", "shuffle", 'gamma', 'laplace'] def randint(low, high=None, size=None, dtype=None, ctx=None, out=None): @@ -437,3 +437,52 @@ def shuffle(x): [0., 1., 2.]]) """ _npi.shuffle(x, out=x) + + +def laplace(loc=0.0, scale=1.0, size=None, dtype=None, ctx=None, out=None): + r"""Draw random samples from a Laplace distribution. + + Samples are distributed according to a Laplace distribution parametrized + by *loc* (mean) and *scale* (the exponential decay). + + + Parameters + ---------- + loc : float, The position of the distribution peak. + + scale : float, the exponential decay. + + size : int or tuple of ints, optional. Output shape. If the given shape is, e.g., (m, n, k), then m * n * k samples are drawn. Default is None, in which case a single value is returned. + + dtype : {'float16', 'float32', 'float64'}, optional + Data type of output samples. Default is 'float32' + ctx : Context, optional + Device context of output. Default is current context. + out : ``ndarray``, optional + Store output to an existing ``ndarray``. + + Returns + ------- + out : ndarray + Drawn samples from the parameterized Laplace distribution. + """ + from ...numpy import ndarray as np_ndarray + input_type = (isinstance(loc, np_ndarray), isinstance(scale, np_ndarray)) + if dtype is None: + dtype = 'float32' + if ctx is None: + ctx = current_context() + if size == (): + size = None + if input_type == (True, True): + return _npi.laplace(loc, scale, loc=None, scale=None, size=size, + ctx=ctx, dtype=dtype, out=out) + elif input_type == (False, True): + return _npi.laplace(scale, loc=loc, scale=None, size=size, + ctx=ctx, dtype=dtype, out=out) + elif input_type == (True, False): + return _npi.laplace(loc, loc=None, scale=scale, size=size, + ctx=ctx, dtype=dtype, out=out) + else: + return _npi.laplace(loc=loc, scale=scale, size=size, + ctx=ctx, dtype=dtype, out=out) \ No newline at end of file diff --git a/python/mxnet/numpy/random.py b/python/mxnet/numpy/random.py index 198f2fcb4389..c4a22f815a03 100644 --- a/python/mxnet/numpy/random.py +++ b/python/mxnet/numpy/random.py @@ -433,3 +433,32 @@ def randn(*size, **kwargs): for s in size: output_shape += (s,) return _mx_nd_np.random.normal(0, 1, size=output_shape, **kwargs) + +def laplace(loc=0.0, scale=1.0, size=None, dtype=None, ctx=None, out=None): + r"""Draw random samples from a Laplace distribution. + + Samples are distributed according to a Laplace distribution parametrized + by *loc* (mean) and *scale* (the exponential decay). + + + Parameters + ---------- + loc : float, The position of the distribution peak. + + scale : float, the exponential decay. + + size : int or tuple of ints, optional. Output shape. If the given shape is, e.g., (m, n, k), then m * n * k samples are drawn. Default is None, in which case a single value is returned. + + dtype : {'float16', 'float32', 'float64'}, optional + Data type of output samples. Default is 'float32' + ctx : Context, optional + Device context of output. Default is current context. + out : ``ndarray``, optional + Store output to an existing ``ndarray``. + + Returns + ------- + out : ndarray + Drawn samples from the parameterized Laplace distribution. + """ + return _mx_nd_np.random.laplace(loc, scale, size, dtype, ctx, out) diff --git a/src/operator/numpy/random/np_laplace_op.cc b/src/operator/numpy/random/np_laplace_op.cc new file mode 100644 index 000000000000..90d4a0f146c1 --- /dev/null +++ b/src/operator/numpy/random/np_laplace_op.cc @@ -0,0 +1,105 @@ +/* + * 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. + */ + +/*! + * Copyright (c) 2019 by Contributors + * \file np_laplace_op.cc + * \brief Operator for numpy sampling from Laplace distributions + */ +#include "./np_laplace_op.h" + +namespace mxnet { + namespace op { + + DMLC_REGISTER_PARAMETER(NumpyLaplaceParam); + + NNVM_REGISTER_OP(_npi_laplace) + .describe("numpy behavior Laplace") + .set_num_inputs( + [](const nnvm::NodeAttrs& attrs) { + const NumpyLaplaceParam& param = nnvm::get(attrs.parsed); + int num_inputs = 2; + if (param.loc.has_value()) num_inputs -= 1; + if (param.scale.has_value()) num_inputs -= 1; + return num_inputs; + } + ) + .set_num_outputs(1) + .set_attr("FListInputNames", + [](const NodeAttrs& attrs) { + const NumpyLaplaceParam& param = nnvm::get(attrs.parsed); + int num_inputs = 2; + if (param.loc.has_value()) num_inputs -= 1; + if (param.scale.has_value()) num_inputs -= 1; + if (num_inputs == 0) return std::vector(); + if (num_inputs == 1) return std::vector{"input1"}; +return std::vector{"input1", "input2"}; +}) +.set_attr_parser(ParamParser) +.set_attr("FInferShape", TwoparamsDistOpShape) +.set_attr("FInferType", NumpyLaplaceOpType) +.set_attr("FResourceRequest", +[](const nnvm::NodeAttrs& attrs) { +return std::vector{ +ResourceRequest::kRandom, ResourceRequest::kTempSpace}; +}) +.set_attr("FCompute", NumpyLaplaceForward) +.set_attr("FGradient", MakeZeroGradNodes) +.add_argument("input1", "NDArray-or-Symbol", "Source input") +.add_argument("input2", "NDArray-or-Symbol", "Source input") +.add_arguments(NumpyLaplaceParam::__FIELDS__()); + +NNVM_REGISTER_OP(_npi_laplace_n) +.describe("numpy behavior laplace") +.set_num_inputs( +[](const nnvm::NodeAttrs& attrs) { +const NumpyLaplaceParam& param = nnvm::get(attrs.parsed); +int num_inputs = 2; +if (param.loc.has_value()) num_inputs -= 1; +if (param.scale.has_value()) num_inputs -= 1; +return num_inputs; +} +) +.set_num_outputs(1) +.set_attr("FListInputNames", +[](const NodeAttrs& attrs) { +const NumpyLaplaceParam& param = nnvm::get(attrs.parsed); +int num_inputs = 2; +if (param.loc.has_value()) num_inputs -= 1; +if (param.scale.has_value()) num_inputs -= 1; +if (num_inputs == 0) return std::vector(); +if (num_inputs == 1) return std::vector{"input1"}; +return std::vector{"input1", "input2"}; +}) +.set_attr_parser(ParamParser) +.set_attr("FInferShape", TwoparamsDistOpConcatShape) +.set_attr("FInferType", NumpyLaplaceOpType) +.set_attr("FResourceRequest", +[](const nnvm::NodeAttrs& attrs) { +return std::vector{ +ResourceRequest::kRandom, ResourceRequest::kTempSpace}; +}) +.set_attr("FCompute", NumpyLaplaceForward) +.set_attr("FGradient", MakeZeroGradNodes) +.add_argument("input1", "NDArray-or-Symbol", "Source input") +.add_argument("input2", "NDArray-or-Symbol", "Source input") +.add_arguments(NumpyLaplaceParam::__FIELDS__()); + +} // namespace op +} // namespace mxnet diff --git a/src/operator/numpy/random/np_laplace_op.cu b/src/operator/numpy/random/np_laplace_op.cu new file mode 100644 index 000000000000..2b199e4f01d3 --- /dev/null +++ b/src/operator/numpy/random/np_laplace_op.cu @@ -0,0 +1,35 @@ +/* + * 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. + */ + +/*! + * Copyright (c) 2019 by Contributors + * \file np_laplace_op.cu + * \brief Operator for numpy sampling from Laplace distributions + */ + +#include "./np_laplace_op.h" + +namespace mxnet { +namespace op { + +NNVM_REGISTER_OP(_npi_laplace) +.set_attr("FCompute", NumpyLaplaceForward); + +} // namespace op +} // namespace mxnet diff --git a/src/operator/numpy/random/np_laplace_op.h b/src/operator/numpy/random/np_laplace_op.h new file mode 100644 index 000000000000..deab5c61c445 --- /dev/null +++ b/src/operator/numpy/random/np_laplace_op.h @@ -0,0 +1,219 @@ +/* + * 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. + */ + +/*! + * Copyright (c) 2019 by Contributors + * \file np_laplace_op.h + * \brief Operator for numpy sampling from Laplace distributions + */ + #ifndef MXNET_OPERATOR_NUMPY_RANDOM_NP_LAPLACE_OP_H_ +#define MXNET_OPERATOR_NUMPY_RANDOM_NP_LAPLACE_OP_H_ + +#include +#include +#include +#include +#include "../../elemwise_op_common.h" +#include "../../mshadow_op.h" +#include "../../mxnet_op.h" +#include "../../operator_common.h" +#include "../../tensor/elemwise_binary_broadcast_op.h" +#include "./dist_common.h" + +namespace mxnet { +namespace op { + +struct NumpyLaplaceParam : public dmlc::Parameter { + dmlc::optional loc; + dmlc::optional scale; + std::string ctx; + int dtype; + dmlc::optional> size; + DMLC_DECLARE_PARAMETER(NumpyLaplaceParam) { + DMLC_DECLARE_FIELD(loc); + DMLC_DECLARE_FIELD(scale); + DMLC_DECLARE_FIELD(size) + .set_default(dmlc::optional>()) + .describe( + "Output shape. If the given shape is, " + "e.g., (m, n, k), then m * n * k samples are drawn. " + "Default is None, in which case a single value is returned."); + DMLC_DECLARE_FIELD(ctx).set_default("cpu").describe( + "Context of output, in format [cpu|gpu|cpu_pinned](n)." + " Only used for imperative calls."); + DMLC_DECLARE_FIELD(dtype) + .add_enum("float32", mshadow::kFloat32) + .add_enum("float64", mshadow::kFloat64) + .add_enum("float16", mshadow::kFloat16) + .set_default(mshadow::kFloat32) + .describe( + "DType of the output in case this can't be inferred. " + "Defaults to float32 if not defined (dtype=None)."); + } +}; + +inline bool NumpyLaplaceOpType(const nnvm::NodeAttrs &attrs, + std::vector *in_attrs, + std::vector *out_attrs) { + const NumpyLaplaceParam ¶m = nnvm::get(attrs.parsed); + int otype = param.dtype; + if (otype != -1) { + (*out_attrs)[0] = otype; + } else { + (*out_attrs)[0] = mshadow::kFloat32; + } + return true; +} + +namespace mxnet_op { + +template +struct laplace_kernel { + MSHADOW_XINLINE static void Map(index_t i, const Shape &lstride, + const Shape &hstride, + const Shape &oshape, IType *loc, + IType *scale, float *uniforms, OType *out) { + Shape coord = unravel(i, oshape); + auto lidx = static_cast(dot(coord, lstride)); + auto hidx = static_cast(dot(coord, hstride)); + IType loc_value = loc[lidx]; + IType scale_value = scale[hidx]; + if(uniforms[i]<0.5){ + out[i]=loc_value+scale_value*log(2*uniforms[i]); + }else{ + out[i]=loc_value-scale_value*log(2*(1-uniforms[i])); + } + } +}; + +template +struct laplace_one_scalar_kernel { + MSHADOW_XINLINE static void Map(index_t i, int scalar_pos, + const Shape &stride, + const Shape &oshape, IType *array, + float scalar, float *uniforms, OType *out) { + Shape coord = unravel(i, oshape); + auto idx = static_cast(dot(coord, stride)); + IType loc_value; + IType scale_value; + if (scalar_pos == 0) { + loc_value = scalar; + scale_value = array[idx]; + } else { + loc_value = array[idx]; + scale_value = scalar; + } + if(uniforms[i]<0.5){ + out[i]=loc_value+scale_value*log(2*uniforms[i]); + }else{ + out[i]=loc_value-scale_value*log(2*(1-uniforms[i])); + } + } +}; + +template +struct laplace_two_scalar_kernel { + MSHADOW_XINLINE static void Map(index_t i, float loc, float scale, + float *uniforms, OType *out) { + if(uniforms[i]<0.5){ + out[i]=loc+scale*log(2*uniforms[i]); + }else{ + out[i]=loc-scale*log(2*(1-uniforms[i])); + } + } +}; +} // namespace mxnet_op + +template +void NumpyLaplaceForward(const nnvm::NodeAttrs &attrs, + const OpContext &ctx, + const std::vector &inputs, + const std::vector &req, + const std::vector &outputs) { + using namespace mshadow; + using namespace mxnet_op; + const NumpyLaplaceParam ¶m = nnvm::get(attrs.parsed); + CHECK_EQ(outputs.size(), 1); + Stream *s = ctx.get_stream(); + + // Generate base random number. + Random *prnd = ctx.requested[0].get_random(s); + Tensor laplace_tensor = + ctx.requested[1].get_space_typed(Shape1(outputs[0].Size()), + s); + prnd->SampleUniform(&laplace_tensor, 0, 1); + mxnet::TShape new_lshape, new_hshape, new_oshape; + + // [scalar scalar] case + if (inputs.size() == 0U) { + MSHADOW_TYPE_SWITCH(outputs[0].type_flag_, OType, { + Kernel, xpu>::Launch( + s, outputs[0].Size(), param.loc.value(), param.scale.value(), + laplace_tensor.dptr_, outputs[0].dptr()); + }); + } else if (inputs.size() == 1U) { + // [scalar tensor], [tensor scalar] case + int ndim = FillShape(inputs[0].shape_, inputs[0].shape_, outputs[0].shape_, + &new_lshape, &new_lshape, &new_oshape); + int scalar_pos; + float scalar_value; + // int type_flag = param.t; + if (param.loc.has_value()) { + scalar_pos = 0; + scalar_value = param.loc.value(); + } else { + scalar_pos = 1; + scalar_value = param.scale.value(); + } + MSHADOW_TYPE_SWITCH(inputs[0].type_flag_, IType, { + MSHADOW_TYPE_SWITCH(outputs[0].type_flag_, OType, { + BROADCAST_NDIM_SWITCH(ndim, NDim, { + Shape oshape = new_oshape.get(); + Shape stride = calc_stride(new_lshape.get()); + Kernel, xpu>::Launch( + s, outputs[0].Size(), scalar_pos, stride, oshape, + inputs[0].dptr(), scalar_value, laplace_tensor.dptr_, + outputs[0].dptr()); + }); + }); + }); + } else if (inputs.size() == 2U) { + // [tensor tensor] case + int ndim = FillShape(inputs[0].shape_, inputs[1].shape_, outputs[0].shape_, + &new_lshape, &new_hshape, &new_oshape); + MSHADOW_TYPE_SWITCH(inputs[0].type_flag_, IType, { + MSHADOW_TYPE_SWITCH(outputs[0].type_flag_, OType, { + BROADCAST_NDIM_SWITCH(ndim, NDim, { + Shape oshape = new_oshape.get(); + Shape lstride = calc_stride(new_lshape.get()); + Shape hstride = calc_stride(new_hshape.get()); + Kernel, xpu>::Launch( + s, outputs[0].Size(), lstride, hstride, oshape, + inputs[0].dptr(), inputs[1].dptr(), + laplace_tensor.dptr_, outputs[0].dptr()); + }); + }); + }); + } +} + +} // namespace op +} // namespace mxnet + +#endif // MXNET_OPERATOR_NUMPY_RANDOM_NP_UNIFORM_OP_H_ From 2de8ac4369cd5b397595278d75739faa3971542a Mon Sep 17 00:00:00 2001 From: AntiZpvoh Date: Wed, 15 Jan 2020 01:26:36 +0800 Subject: [PATCH 02/22] NumPy Laplace Distribution Backend style rectified Signed-off-by: AntiZpvoh --- src/operator/numpy/random/np_laplace_op.cc | 84 +++++++++++----------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/src/operator/numpy/random/np_laplace_op.cc b/src/operator/numpy/random/np_laplace_op.cc index 90d4a0f146c1..601016c884ae 100644 --- a/src/operator/numpy/random/np_laplace_op.cc +++ b/src/operator/numpy/random/np_laplace_op.cc @@ -25,40 +25,40 @@ #include "./np_laplace_op.h" namespace mxnet { - namespace op { +namespace op { - DMLC_REGISTER_PARAMETER(NumpyLaplaceParam); +DMLC_REGISTER_PARAMETER(NumpyLaplaceParam); - NNVM_REGISTER_OP(_npi_laplace) - .describe("numpy behavior Laplace") - .set_num_inputs( - [](const nnvm::NodeAttrs& attrs) { - const NumpyLaplaceParam& param = nnvm::get(attrs.parsed); - int num_inputs = 2; - if (param.loc.has_value()) num_inputs -= 1; - if (param.scale.has_value()) num_inputs -= 1; - return num_inputs; - } - ) - .set_num_outputs(1) - .set_attr("FListInputNames", - [](const NodeAttrs& attrs) { +NNVM_REGISTER_OP(_npi_laplace) +.describe("numpy behavior Laplace") +.set_num_inputs( + [](const nnvm::NodeAttrs& attrs) { + const NumpyLaplaceParam& param = nnvm::get(attrs.parsed); + int num_inputs = 2; + if (param.loc.has_value()) num_inputs -= 1; + if (param.scale.has_value()) num_inputs -= 1; + return num_inputs; + } +) +.set_num_outputs(1) +.set_attr("FListInputNames", + [](const NodeAttrs& attrs) { const NumpyLaplaceParam& param = nnvm::get(attrs.parsed); int num_inputs = 2; if (param.loc.has_value()) num_inputs -= 1; if (param.scale.has_value()) num_inputs -= 1; if (num_inputs == 0) return std::vector(); if (num_inputs == 1) return std::vector{"input1"}; -return std::vector{"input1", "input2"}; -}) + return std::vector{"input1", "input2"}; + }) .set_attr_parser(ParamParser) .set_attr("FInferShape", TwoparamsDistOpShape) .set_attr("FInferType", NumpyLaplaceOpType) .set_attr("FResourceRequest", -[](const nnvm::NodeAttrs& attrs) { -return std::vector{ -ResourceRequest::kRandom, ResourceRequest::kTempSpace}; -}) + [](const nnvm::NodeAttrs& attrs) { + return std::vector{ + ResourceRequest::kRandom, ResourceRequest::kTempSpace}; + }) .set_attr("FCompute", NumpyLaplaceForward) .set_attr("FGradient", MakeZeroGradNodes) .add_argument("input1", "NDArray-or-Symbol", "Source input") @@ -68,33 +68,33 @@ ResourceRequest::kRandom, ResourceRequest::kTempSpace}; NNVM_REGISTER_OP(_npi_laplace_n) .describe("numpy behavior laplace") .set_num_inputs( -[](const nnvm::NodeAttrs& attrs) { -const NumpyLaplaceParam& param = nnvm::get(attrs.parsed); -int num_inputs = 2; -if (param.loc.has_value()) num_inputs -= 1; -if (param.scale.has_value()) num_inputs -= 1; -return num_inputs; -} + [](const nnvm::NodeAttrs& attrs) { + const NumpyLaplaceParam& param = nnvm::get(attrs.parsed); + int num_inputs = 2; + if (param.loc.has_value()) num_inputs -= 1; + if (param.scale.has_value()) num_inputs -= 1; + return num_inputs; + } ) .set_num_outputs(1) .set_attr("FListInputNames", -[](const NodeAttrs& attrs) { -const NumpyLaplaceParam& param = nnvm::get(attrs.parsed); -int num_inputs = 2; -if (param.loc.has_value()) num_inputs -= 1; -if (param.scale.has_value()) num_inputs -= 1; -if (num_inputs == 0) return std::vector(); -if (num_inputs == 1) return std::vector{"input1"}; -return std::vector{"input1", "input2"}; -}) + [](const NodeAttrs& attrs) { + const NumpyLaplaceParam& param = nnvm::get(attrs.parsed); + int num_inputs = 2; + if (param.loc.has_value()) num_inputs -= 1; + if (param.scale.has_value()) num_inputs -= 1; + if (num_inputs == 0) return std::vector(); + if (num_inputs == 1) return std::vector{"input1"}; + return std::vector{"input1", "input2"}; + }) .set_attr_parser(ParamParser) .set_attr("FInferShape", TwoparamsDistOpConcatShape) .set_attr("FInferType", NumpyLaplaceOpType) .set_attr("FResourceRequest", -[](const nnvm::NodeAttrs& attrs) { -return std::vector{ -ResourceRequest::kRandom, ResourceRequest::kTempSpace}; -}) + [](const nnvm::NodeAttrs& attrs) { + return std::vector{ + ResourceRequest::kRandom, ResourceRequest::kTempSpace}; + }) .set_attr("FCompute", NumpyLaplaceForward) .set_attr("FGradient", MakeZeroGradNodes) .add_argument("input1", "NDArray-or-Symbol", "Source input") From b789cd76490490b369a18b445104a05de81449b5 Mon Sep 17 00:00:00 2001 From: AntiZpvoh Date: Wed, 15 Jan 2020 01:33:44 +0800 Subject: [PATCH 03/22] NumPy Laplace Distribution Frontend modified Signed-off-by: AntiZpvoh --- python/mxnet/numpy/random.py | 3 +- python/mxnet/symbol/numpy/random.py | 50 ++++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/python/mxnet/numpy/random.py b/python/mxnet/numpy/random.py index c4a22f815a03..7199458dba99 100644 --- a/python/mxnet/numpy/random.py +++ b/python/mxnet/numpy/random.py @@ -21,7 +21,7 @@ from ..ndarray import numpy as _mx_nd_np __all__ = ["randint", "uniform", "normal", "choice", "rand", "multinomial", "shuffle", "randn", - "gamma"] + "gamma", "laplace"] def randint(low, high=None, size=None, dtype=None, ctx=None, out=None): @@ -440,7 +440,6 @@ def laplace(loc=0.0, scale=1.0, size=None, dtype=None, ctx=None, out=None): Samples are distributed according to a Laplace distribution parametrized by *loc* (mean) and *scale* (the exponential decay). - Parameters ---------- loc : float, The position of the distribution peak. diff --git a/python/mxnet/symbol/numpy/random.py b/python/mxnet/symbol/numpy/random.py index c6b23b507d87..54e9a69c866c 100644 --- a/python/mxnet/symbol/numpy/random.py +++ b/python/mxnet/symbol/numpy/random.py @@ -21,7 +21,7 @@ from ...context import current_context from . import _internal as _npi -__all__ = ['randint', 'uniform', 'normal', 'rand', 'shuffle', 'gamma'] +__all__ = ['randint', 'uniform', 'normal', 'rand', 'shuffle', 'gamma', 'laplace'] def randint(low, high=None, size=None, dtype=None, ctx=None, out=None): @@ -290,6 +290,54 @@ def choice(a, size=None, replace=True, p=None, ctx=None, out=None): return _npi.choice(p, a=a, size=size, replace=replace, ctx=ctx, weighted=True, out=out) +def laplace(loc=0.0, scale=1.0, size=None, dtype=None, ctx=None, out=None): + r"""Draw random samples from a Laplace distribution. + + Samples are distributed according to a Laplace distribution parametrized + by *loc* (mean) and *scale* (the exponential decay). + + Parameters + ---------- + loc : float, The position of the distribution peak. + + scale : float, the exponential decay. + + size : int or tuple of ints, optional. Output shape. If the given shape is, e.g., (m, n, k), then m * n * k samples are drawn. Default is None, in which case a single value is returned. + + dtype : {'float16', 'float32', 'float64'}, optional + Data type of output samples. Default is 'float32' + ctx : Context, optional + Device context of output. Default is current context. + out : ``ndarray``, optional + Store output to an existing ``ndarray``. + + Returns + ------- + out : _Symbol (symbol representing `mxnet.numpy.ndarray` in computational graphs) + Drawn samples from the parameterized Laplace distribution. + """ + from ._symbol import _Symbol as np_symbol + input_type = (isinstance(loc, np_symbol), isinstance(scale, np_symbol)) + if dtype is None: + dtype = 'float32' + if ctx is None: + ctx = current_context() + if size == (): + size = None + if input_type == (True, True): + return _npi.laplace(loc, scale, loc=None, scale=None, size=size, + ctx=ctx, dtype=dtype, out=out) + elif input_type == (False, True): + return _npi.laplace(scale, loc=loc, scale=None, size=size, + ctx=ctx, dtype=dtype, out=out) + elif input_type == (True, False): + return _npi.laplace(loc, loc=None, scale=scale, size=size, + ctx=ctx, dtype=dtype, out=out) + else: + return _npi.laplace(loc=loc, scale=scale, size=size, + ctx=ctx, dtype=dtype, out=out) + + def gamma(shape, scale=1.0, size=None, dtype=None, ctx=None, out=None): """Draw samples from a Gamma distribution. From 97a5d352f99d8f841d277ed747791405406b05b4 Mon Sep 17 00:00:00 2001 From: AntiZpvoh Date: Wed, 15 Jan 2020 13:16:20 +0800 Subject: [PATCH 04/22] Laplece op nightly test and normal op test correction Signed-off-by: AntiZpvoh --- tests/nightly/test_np_random.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/tests/nightly/test_np_random.py b/tests/nightly/test_np_random.py index d086ac4b08d6..232cf4b03d0d 100644 --- a/tests/nightly/test_np_random.py +++ b/tests/nightly/test_np_random.py @@ -71,7 +71,7 @@ def test_np_normal(): num_buckets = 5 for dtype in types: for loc, scale in [(0.0, 1.0), (1.0, 5.0)]: - buckets, probs = gen_buckets_probs_with_ppf(lambda x: ss.norm.pdf(x, loc=low, scale=scale), num_buckets) + buckets, probs = gen_buckets_probs_with_ppf(lambda x: ss.norm.ppf(x, loc=loc, scale=scale), num_buckets) buckets = np.array(buckets, dtype=dtype).tolist() probs = [(buckets[i][1] - buckets[i][0])/scale for i in range(num_buckets)] generator_mx_np = lambda x: np.random.normal(loc, scale, size=x, ctx=ctx, dtype=dtype).asnumpy() @@ -105,6 +105,25 @@ def generator_mx(x): return np.random.gamma( nsamples=samples, nrepeat=trials) +@retry(5) +@with_seed() +@use_np +def test_np_laplace(): + types = [None, "float32", "float64"] + ctx = mx.context.current_context() + samples = 1000000 + # Generation test + trials = 8 + num_buckets = 5 + for dtype in types: + for loc, scale in [(0.0, 1.0), (1.0, 5.0)]: + buckets, probs = gen_buckets_probs_with_ppf(lambda x: ss.laplace.ppf(x, loc=loc, scale=scale), num_buckets) + buckets = np.array(buckets, dtype=dtype).tolist() + probs = [(buckets[i][1] - buckets[i][0])/scale for i in range(num_buckets)] + generator_mx_np = lambda x: np.random.laplace(loc, scale, size=x, ctx=ctx, dtype=dtype).asnumpy() + verify_generator(generator=generator_mx_np, buckets=buckets, probs=probs, nsamples=samples, nrepeat=trials) + + if __name__ == '__main__': import nose nose.runmodule() From 94087e68daa9daea6eb415f9a30d62898ba03470 Mon Sep 17 00:00:00 2001 From: AntiZpvoh Date: Wed, 15 Jan 2020 14:29:29 +0800 Subject: [PATCH 05/22] NumPy Laplace Distribution unit test and code style Signed-off-by: AntiZpvoh --- src/operator/numpy/random/np_laplace_op.h | 33 +++++++++++------------ tests/python/unittest/test_numpy_op.py | 2 +- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/operator/numpy/random/np_laplace_op.h b/src/operator/numpy/random/np_laplace_op.h index deab5c61c445..e3ae49fa46a1 100644 --- a/src/operator/numpy/random/np_laplace_op.h +++ b/src/operator/numpy/random/np_laplace_op.h @@ -22,7 +22,7 @@ * \file np_laplace_op.h * \brief Operator for numpy sampling from Laplace distributions */ - #ifndef MXNET_OPERATOR_NUMPY_RANDOM_NP_LAPLACE_OP_H_ +#ifndef MXNET_OPERATOR_NUMPY_RANDOM_NP_LAPLACE_OP_H_ #define MXNET_OPERATOR_NUMPY_RANDOM_NP_LAPLACE_OP_H_ #include @@ -82,7 +82,6 @@ inline bool NumpyLaplaceOpType(const nnvm::NodeAttrs &attrs, } namespace mxnet_op { - template struct laplace_kernel { MSHADOW_XINLINE static void Map(index_t i, const Shape &lstride, @@ -94,10 +93,10 @@ struct laplace_kernel { auto hidx = static_cast(dot(coord, hstride)); IType loc_value = loc[lidx]; IType scale_value = scale[hidx]; - if(uniforms[i]<0.5){ - out[i]=loc_value+scale_value*log(2*uniforms[i]); - }else{ - out[i]=loc_value-scale_value*log(2*(1-uniforms[i])); + if (uniforms[i] < 0.5) { + out[i] = loc_value + scale_value * log(2 * uniforms[i]); + } else { + out[i] = loc_value - scale_value * log(2 * (1 - uniforms[i])); } } }; @@ -119,11 +118,11 @@ struct laplace_one_scalar_kernel { loc_value = array[idx]; scale_value = scalar; } - if(uniforms[i]<0.5){ - out[i]=loc_value+scale_value*log(2*uniforms[i]); - }else{ - out[i]=loc_value-scale_value*log(2*(1-uniforms[i])); - } + if (uniforms[i] < 0.5) { + out[i] = loc_value + scale_value * log(2 * uniforms[i]); + } else { + out[i] = loc_value - scale_value * log(2 * (1 - uniforms[i])); + } } }; @@ -131,11 +130,11 @@ template struct laplace_two_scalar_kernel { MSHADOW_XINLINE static void Map(index_t i, float loc, float scale, float *uniforms, OType *out) { - if(uniforms[i]<0.5){ - out[i]=loc+scale*log(2*uniforms[i]); - }else{ - out[i]=loc-scale*log(2*(1-uniforms[i])); - } + if (uniforms[i] < 0.5) { + out[i] = loc + scale * log(2 * uniforms[i]); + } else { + out[i] = loc - scale * log(2 * (1 - uniforms[i])); + } } }; } // namespace mxnet_op @@ -216,4 +215,4 @@ void NumpyLaplaceForward(const nnvm::NodeAttrs &attrs, } // namespace op } // namespace mxnet -#endif // MXNET_OPERATOR_NUMPY_RANDOM_NP_UNIFORM_OP_H_ +#endif // MXNET_OPERATOR_NUMPY_RANDOM_NP_LAPLACE_OP_H_ diff --git a/tests/python/unittest/test_numpy_op.py b/tests/python/unittest/test_numpy_op.py index b25c69385e1e..e3e2aa1f7191 100644 --- a/tests/python/unittest/test_numpy_op.py +++ b/tests/python/unittest/test_numpy_op.py @@ -3279,7 +3279,7 @@ def hybrid_forward(self, F, param1, param2): def test_np_random(): shapes = [(), (1,), (2, 3), (4, 0, 5), 6, (7, 8), None] dtypes = ['float16', 'float32', 'float64'] - op_names = ['uniform', 'normal', 'gamma'] + op_names = ['uniform', 'normal', 'gamma', 'laplace'] for shape in shapes: for dtype in dtypes: for op_name in op_names: From eec4ec25bf78607ec65d7dcd66d10a85a3434fd8 Mon Sep 17 00:00:00 2001 From: AntiZpvoh Date: Wed, 15 Jan 2020 16:11:32 +0800 Subject: [PATCH 06/22] Register uniform_n in CUDA Signed-off-by: AntiZpvoh --- src/operator/numpy/random/np_laplace_op.cu | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/operator/numpy/random/np_laplace_op.cu b/src/operator/numpy/random/np_laplace_op.cu index 2b199e4f01d3..f7aa104b6397 100644 --- a/src/operator/numpy/random/np_laplace_op.cu +++ b/src/operator/numpy/random/np_laplace_op.cu @@ -31,5 +31,8 @@ namespace op { NNVM_REGISTER_OP(_npi_laplace) .set_attr("FCompute", NumpyLaplaceForward); +NNVM_REGISTER_OP(_npi_uniform_n) +.set_attr("FCompute", NumpyLaplaceForward); + } // namespace op } // namespace mxnet From 14dd8b251eb7cdb33453602bca5c0a054f575731 Mon Sep 17 00:00:00 2001 From: AntiZpvoh Date: Wed, 15 Jan 2020 16:28:25 +0800 Subject: [PATCH 07/22] Delete the registering of Laplace_n Signed-off-by: AntiZpvoh --- src/operator/numpy/random/np_laplace_op.cc | 36 ---------------------- src/operator/numpy/random/np_laplace_op.cu | 3 -- 2 files changed, 39 deletions(-) diff --git a/src/operator/numpy/random/np_laplace_op.cc b/src/operator/numpy/random/np_laplace_op.cc index 601016c884ae..9d147aca7009 100644 --- a/src/operator/numpy/random/np_laplace_op.cc +++ b/src/operator/numpy/random/np_laplace_op.cc @@ -65,41 +65,5 @@ NNVM_REGISTER_OP(_npi_laplace) .add_argument("input2", "NDArray-or-Symbol", "Source input") .add_arguments(NumpyLaplaceParam::__FIELDS__()); -NNVM_REGISTER_OP(_npi_laplace_n) -.describe("numpy behavior laplace") -.set_num_inputs( - [](const nnvm::NodeAttrs& attrs) { - const NumpyLaplaceParam& param = nnvm::get(attrs.parsed); - int num_inputs = 2; - if (param.loc.has_value()) num_inputs -= 1; - if (param.scale.has_value()) num_inputs -= 1; - return num_inputs; - } -) -.set_num_outputs(1) -.set_attr("FListInputNames", - [](const NodeAttrs& attrs) { - const NumpyLaplaceParam& param = nnvm::get(attrs.parsed); - int num_inputs = 2; - if (param.loc.has_value()) num_inputs -= 1; - if (param.scale.has_value()) num_inputs -= 1; - if (num_inputs == 0) return std::vector(); - if (num_inputs == 1) return std::vector{"input1"}; - return std::vector{"input1", "input2"}; - }) -.set_attr_parser(ParamParser) -.set_attr("FInferShape", TwoparamsDistOpConcatShape) -.set_attr("FInferType", NumpyLaplaceOpType) -.set_attr("FResourceRequest", - [](const nnvm::NodeAttrs& attrs) { - return std::vector{ - ResourceRequest::kRandom, ResourceRequest::kTempSpace}; - }) -.set_attr("FCompute", NumpyLaplaceForward) -.set_attr("FGradient", MakeZeroGradNodes) -.add_argument("input1", "NDArray-or-Symbol", "Source input") -.add_argument("input2", "NDArray-or-Symbol", "Source input") -.add_arguments(NumpyLaplaceParam::__FIELDS__()); - } // namespace op } // namespace mxnet diff --git a/src/operator/numpy/random/np_laplace_op.cu b/src/operator/numpy/random/np_laplace_op.cu index f7aa104b6397..2b199e4f01d3 100644 --- a/src/operator/numpy/random/np_laplace_op.cu +++ b/src/operator/numpy/random/np_laplace_op.cu @@ -31,8 +31,5 @@ namespace op { NNVM_REGISTER_OP(_npi_laplace) .set_attr("FCompute", NumpyLaplaceForward); -NNVM_REGISTER_OP(_npi_uniform_n) -.set_attr("FCompute", NumpyLaplaceForward); - } // namespace op } // namespace mxnet From 96c91306949753f3c5c9000bca4a9e3f153b65b3 Mon Sep 17 00:00:00 2001 From: AntiZpvoh Date: Thu, 16 Jan 2020 12:05:07 +0800 Subject: [PATCH 08/22] fix some alignment and indentation problems Signed-off-by: AntiZpvoh --- python/mxnet/symbol/numpy/random.py | 8 ++++---- src/operator/numpy/random/np_laplace_op.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/python/mxnet/symbol/numpy/random.py b/python/mxnet/symbol/numpy/random.py index 54e9a69c866c..745ebcc17fea 100644 --- a/python/mxnet/symbol/numpy/random.py +++ b/python/mxnet/symbol/numpy/random.py @@ -326,16 +326,16 @@ def laplace(loc=0.0, scale=1.0, size=None, dtype=None, ctx=None, out=None): size = None if input_type == (True, True): return _npi.laplace(loc, scale, loc=None, scale=None, size=size, - ctx=ctx, dtype=dtype, out=out) + ctx=ctx, dtype=dtype, out=out) elif input_type == (False, True): return _npi.laplace(scale, loc=loc, scale=None, size=size, - ctx=ctx, dtype=dtype, out=out) + ctx=ctx, dtype=dtype, out=out) elif input_type == (True, False): return _npi.laplace(loc, loc=None, scale=scale, size=size, - ctx=ctx, dtype=dtype, out=out) + ctx=ctx, dtype=dtype, out=out) else: return _npi.laplace(loc=loc, scale=scale, size=size, - ctx=ctx, dtype=dtype, out=out) + ctx=ctx, dtype=dtype, out=out) def gamma(shape, scale=1.0, size=None, dtype=None, ctx=None, out=None): diff --git a/src/operator/numpy/random/np_laplace_op.h b/src/operator/numpy/random/np_laplace_op.h index e3ae49fa46a1..359a4024ee38 100644 --- a/src/operator/numpy/random/np_laplace_op.h +++ b/src/operator/numpy/random/np_laplace_op.h @@ -49,7 +49,7 @@ struct NumpyLaplaceParam : public dmlc::Parameter { DMLC_DECLARE_FIELD(loc); DMLC_DECLARE_FIELD(scale); DMLC_DECLARE_FIELD(size) - .set_default(dmlc::optional>()) + .set_default(dmlc::optional>()) .describe( "Output shape. If the given shape is, " "e.g., (m, n, k), then m * n * k samples are drawn. " From 48cc7d3a7a9218f4dd0f4636bffca115dd485bc5 Mon Sep 17 00:00:00 2001 From: AntiZpvoh Date: Wed, 12 Feb 2020 14:31:04 +0800 Subject: [PATCH 09/22] fix some sanity problems such as too long lines --- python/mxnet/ndarray/numpy/random.py | 6 ++++-- python/mxnet/numpy/random.py | 4 +++- python/mxnet/symbol/numpy/random.py | 4 +++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/python/mxnet/ndarray/numpy/random.py b/python/mxnet/ndarray/numpy/random.py index 5b22f998c65d..e5ffe2b33e88 100644 --- a/python/mxnet/ndarray/numpy/random.py +++ b/python/mxnet/ndarray/numpy/random.py @@ -794,7 +794,9 @@ def laplace(loc=0.0, scale=1.0, size=None, dtype=None, ctx=None, out=None): scale : float, the exponential decay. - size : int or tuple of ints, optional. Output shape. If the given shape is, e.g., (m, n, k), then m * n * k samples are drawn. Default is None, in which case a single value is returned. + size : int or tuple of ints, optional. Output shape. + If the given shape is, e.g., (m, n, k), then m * n * k samples are drawn. + Default is None, in which case a single value is returned. dtype : {'float16', 'float32', 'float64'}, optional Data type of output samples. Default is 'float32' @@ -827,4 +829,4 @@ def laplace(loc=0.0, scale=1.0, size=None, dtype=None, ctx=None, out=None): ctx=ctx, dtype=dtype, out=out) else: return _npi.laplace(loc=loc, scale=scale, size=size, - ctx=ctx, dtype=dtype, out=out) \ No newline at end of file + ctx=ctx, dtype=dtype, out=out) diff --git a/python/mxnet/numpy/random.py b/python/mxnet/numpy/random.py index 2f39161aae10..7d3b6ff4c676 100644 --- a/python/mxnet/numpy/random.py +++ b/python/mxnet/numpy/random.py @@ -768,7 +768,9 @@ def laplace(loc=0.0, scale=1.0, size=None, dtype=None, ctx=None, out=None): scale : float, the exponential decay. - size : int or tuple of ints, optional. Output shape. If the given shape is, e.g., (m, n, k), then m * n * k samples are drawn. Default is None, in which case a single value is returned. + size : int or tuple of ints, optional. Output shape. + If the given shape is, e.g., (m, n, k), then m * n * k samples are drawn. + Default is None, in which case a single value is returned. dtype : {'float16', 'float32', 'float64'}, optional Data type of output samples. Default is 'float32' diff --git a/python/mxnet/symbol/numpy/random.py b/python/mxnet/symbol/numpy/random.py index fedbaf486b2b..f0d87a05eb5e 100644 --- a/python/mxnet/symbol/numpy/random.py +++ b/python/mxnet/symbol/numpy/random.py @@ -337,7 +337,9 @@ def laplace(loc=0.0, scale=1.0, size=None, dtype=None, ctx=None, out=None): scale : float, the exponential decay. - size : int or tuple of ints, optional. Output shape. If the given shape is, e.g., (m, n, k), then m * n * k samples are drawn. Default is None, in which case a single value is returned. + size : int or tuple of ints, optional. Output shape. + If the given shape is, e.g., (m, n, k), then m * n * k samples are drawn. + Default is None, in which case a single value is returned. dtype : {'float16', 'float32', 'float64'}, optional Data type of output samples. Default is 'float32' From 2d9a72c3d75547ef189e608a7809dbe8726e73ad Mon Sep 17 00:00:00 2001 From: AntiZpvoh Date: Wed, 12 Feb 2020 14:50:10 +0800 Subject: [PATCH 10/22] fix some sanity problems again --- python/mxnet/ndarray/numpy/random.py | 6 +++--- python/mxnet/numpy/random.py | 6 +++--- python/mxnet/symbol/numpy/random.py | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/python/mxnet/ndarray/numpy/random.py b/python/mxnet/ndarray/numpy/random.py index e5ffe2b33e88..c69d9095c22f 100644 --- a/python/mxnet/ndarray/numpy/random.py +++ b/python/mxnet/ndarray/numpy/random.py @@ -794,9 +794,9 @@ def laplace(loc=0.0, scale=1.0, size=None, dtype=None, ctx=None, out=None): scale : float, the exponential decay. - size : int or tuple of ints, optional. Output shape. - If the given shape is, e.g., (m, n, k), then m * n * k samples are drawn. - Default is None, in which case a single value is returned. + size : int or tuple of ints, optional. Output shape. + If the given shape is, e.g., (m, n, k), then m * n * k samples are drawn. + Default is None, in which case a single value is returned. dtype : {'float16', 'float32', 'float64'}, optional Data type of output samples. Default is 'float32' diff --git a/python/mxnet/numpy/random.py b/python/mxnet/numpy/random.py index 7d3b6ff4c676..8800977f6c50 100644 --- a/python/mxnet/numpy/random.py +++ b/python/mxnet/numpy/random.py @@ -768,9 +768,9 @@ def laplace(loc=0.0, scale=1.0, size=None, dtype=None, ctx=None, out=None): scale : float, the exponential decay. - size : int or tuple of ints, optional. Output shape. - If the given shape is, e.g., (m, n, k), then m * n * k samples are drawn. - Default is None, in which case a single value is returned. + size : int or tuple of ints, optional. Output shape. + If the given shape is, e.g., (m, n, k), then m * n * k samples are drawn. + Default is None, in which case a single value is returned. dtype : {'float16', 'float32', 'float64'}, optional Data type of output samples. Default is 'float32' diff --git a/python/mxnet/symbol/numpy/random.py b/python/mxnet/symbol/numpy/random.py index f0d87a05eb5e..1c2c7af7525d 100644 --- a/python/mxnet/symbol/numpy/random.py +++ b/python/mxnet/symbol/numpy/random.py @@ -337,9 +337,9 @@ def laplace(loc=0.0, scale=1.0, size=None, dtype=None, ctx=None, out=None): scale : float, the exponential decay. - size : int or tuple of ints, optional. Output shape. - If the given shape is, e.g., (m, n, k), then m * n * k samples are drawn. - Default is None, in which case a single value is returned. + size : int or tuple of ints, optional. Output shape. + If the given shape is, e.g., (m, n, k), then m * n * k samples are drawn. + Default is None, in which case a single value is returned. dtype : {'float16', 'float32', 'float64'}, optional Data type of output samples. Default is 'float32' From de61812d184c0f6bcafdab3a9ca976e408637967 Mon Sep 17 00:00:00 2001 From: AntiZpvoh Date: Mon, 9 Mar 2020 16:31:33 +0800 Subject: [PATCH 11/22] laplace parmeters form change --- src/operator/numpy/random/np_laplace_op.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/operator/numpy/random/np_laplace_op.h b/src/operator/numpy/random/np_laplace_op.h index 359a4024ee38..cf78f550f654 100644 --- a/src/operator/numpy/random/np_laplace_op.h +++ b/src/operator/numpy/random/np_laplace_op.h @@ -66,6 +66,20 @@ struct NumpyLaplaceParam : public dmlc::Parameter { "DType of the output in case this can't be inferred. " "Defaults to float32 if not defined (dtype=None)."); } + + *void SetAttrDict(std::unordered_map* dict) { + std::ostringstream loc_s, scale_s, size_s, dtype_s; + loc_s << loc; + scale_s << scale; + size_s << size; + dtype_s << dtype; + (*dict)["loc"] = loc_s.str(); + (*dict)["scale"] = scale_s.str(); + (*dict)["size"] = size_s.str(); + (*dict)["dtype"] = dtype_s.str(); + // We do not set ctx, because ctx has been set in dict instead of InitOpParam. + // Setting ctx here results in an error. + } }; inline bool NumpyLaplaceOpType(const nnvm::NodeAttrs &attrs, From 115cc41ca4f84c253ecf7ae3ac1ea184b208e7a3 Mon Sep 17 00:00:00 2001 From: AntiZpvoh Date: Tue, 10 Mar 2020 13:26:42 +0800 Subject: [PATCH 12/22] implement basic laplace function --- .../operator/numpy/random/np_laplace_op.cc | 85 +++++++++++++++++++ src/operator/numpy/random/np_laplace_op.h | 2 +- 2 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 src/api/operator/numpy/random/np_laplace_op.cc diff --git a/src/api/operator/numpy/random/np_laplace_op.cc b/src/api/operator/numpy/random/np_laplace_op.cc new file mode 100644 index 000000000000..5ebfb6a18507 --- /dev/null +++ b/src/api/operator/numpy/random/np_laplace_op.cc @@ -0,0 +1,85 @@ +/* + * 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_init_op.cc + * \brief Implementation of the API of functions in src/operator/numpy/np_init_op.cc + */ +#include +#include +#include "../../utils.h" +#include "../../../../operator/numpy/random/np_laplace_op.h" + +namespace mxnet { + +MXNET_REGISTER_API("_npi.laplace") +.set_body([](runtime::MXNetArgs args, runtime::MXNetRetValue* ret) { + using namespace runtime; + const nnvm::Op* op = Op::Get("_npi_laplace"); + nnvm::NodeAttrs attrs; + op::NumpyLaplaceParam param; + if (args[0].type_code() == kNull) { + param.loc = dmlc::nullopt; + } else { + param.loc = args[0].operator double(); // convert arg to T + } + + if (args[1].type_code() == kNull) { + param.scale = dmlc::nullopt; + } else { + param.scale = args[1].operator double(); // convert arg to T + } + + if (args[2].type_code() == kNull) { + param.size = dmlc::nullopt; + } else { + if (args[2].type_code() == kDLInt) { + param.size = Tuple(1, args[2].operator int64_t()); + } else { + param.size = Tuple(args[2].operator ObjectRef()); + } + } + + if (args[4].type_code() == kNull) { + param.dtype = mshadow::kFloat32; + } else { + param.dtype = String2MXNetTypeWithBool(args[4].operator std::string()); + } + attrs.parsed = std::move(param); + attrs.op = op; + SetAttrDict(&attrs); + if (args[3].type_code() != kNull) { + attrs.dict["ctx"] = args[3].operator std::string(); + } + + NDArray* out = args[5].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, 0, nullptr, &num_outputs, outputs); + if (out) { + // PythonArg(n) designates the nth python argument is to be returned. + // So suppose `out` is the 3rd positional argument, we use PythonArg(2) (0-based index) + *ret = PythonArg(5); + } else { + *ret = ndoutputs[0]; + } +}); + +} // namespace mxnet diff --git a/src/operator/numpy/random/np_laplace_op.h b/src/operator/numpy/random/np_laplace_op.h index cf78f550f654..794f50178747 100644 --- a/src/operator/numpy/random/np_laplace_op.h +++ b/src/operator/numpy/random/np_laplace_op.h @@ -67,7 +67,7 @@ struct NumpyLaplaceParam : public dmlc::Parameter { "Defaults to float32 if not defined (dtype=None)."); } - *void SetAttrDict(std::unordered_map* dict) { + void SetAttrDict(std::unordered_map* dict) { std::ostringstream loc_s, scale_s, size_s, dtype_s; loc_s << loc; scale_s << scale; From 29b0034f430a40f882a14d451538253225aa30d6 Mon Sep 17 00:00:00 2001 From: AntiZpvoh Date: Tue, 10 Mar 2020 14:17:57 +0800 Subject: [PATCH 13/22] add frontend implement and ndarray loc case --- python/mxnet/ndarray/numpy/random.py | 5 +++++ .../operator/numpy/random/np_laplace_op.cc | 20 +++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/python/mxnet/ndarray/numpy/random.py b/python/mxnet/ndarray/numpy/random.py index 309414728ccd..39a0a9789278 100644 --- a/python/mxnet/ndarray/numpy/random.py +++ b/python/mxnet/ndarray/numpy/random.py @@ -20,6 +20,7 @@ from ...context import current_context from . import _internal as _npi from ..ndarray import NDArray +from . import _api_internal __all__ = ['randint', 'uniform', 'normal', "choice", "rand", "multinomial", "multivariate_normal", @@ -1055,3 +1056,7 @@ def laplace(loc=0.0, scale=1.0, size=None, dtype=None, ctx=None, out=None): else: return _npi.laplace(loc=loc, scale=scale, size=size, ctx=ctx, dtype=dtype, out=out) + + +def laplace_v2(loc=0.0, scale=1.0, size=None, dtype=None, ctx=None, out=None): + return _api_internal.laplace(loc, scale, size, dtype, ctx, out) diff --git a/src/api/operator/numpy/random/np_laplace_op.cc b/src/api/operator/numpy/random/np_laplace_op.cc index 5ebfb6a18507..f639d2739a5e 100644 --- a/src/api/operator/numpy/random/np_laplace_op.cc +++ b/src/api/operator/numpy/random/np_laplace_op.cc @@ -34,10 +34,16 @@ MXNET_REGISTER_API("_npi.laplace") const nnvm::Op* op = Op::Get("_npi_laplace"); nnvm::NodeAttrs attrs; op::NumpyLaplaceParam param; + + NDArray* in; + if (args[0].type_code() == kNull) { param.loc = dmlc::nullopt; - } else { + } else if (args[0].type_code() == kDLInt) { param.loc = args[0].operator double(); // convert arg to T + } else if (args[0].type_code() == kNDArrayHandle){ + param.loc = dmlc::nullopt; + in = args[0].operator mxnet::NDArray *(); } if (args[1].type_code() == kNull) { @@ -50,9 +56,9 @@ MXNET_REGISTER_API("_npi.laplace") param.size = dmlc::nullopt; } else { if (args[2].type_code() == kDLInt) { - param.size = Tuple(1, args[2].operator int64_t()); + param.size = mxnet::Tuple(1, args[2].operator int64_t()); } else { - param.size = Tuple(args[2].operator ObjectRef()); + param.size = mxnet::Tuple(args[2].operator ObjectRef()); } } @@ -68,11 +74,17 @@ MXNET_REGISTER_API("_npi.laplace") attrs.dict["ctx"] = args[3].operator std::string(); } + int num_inputs = 2; + if (param.loc.has_value()) num_inputs -= 1; + if (param.scale.has_value()) num_inputs -= 1; + + NDArray** inputs = in == nullptr ? nullptr : ∈ + NDArray* out = args[5].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, 0, nullptr, &num_outputs, outputs); + auto ndoutputs = Invoke(op, &attrs, num_inputs, inputs, &num_outputs, outputs); if (out) { // PythonArg(n) designates the nth python argument is to be returned. // So suppose `out` is the 3rd positional argument, we use PythonArg(2) (0-based index) From d1e968bc39740f371c47fba85f419a4e69fe1f02 Mon Sep 17 00:00:00 2001 From: AntiZpvoh Date: Tue, 10 Mar 2020 15:01:17 +0800 Subject: [PATCH 14/22] complete the frontend --- python/mxnet/ndarray/numpy/random.py | 21 ------------------- .../operator/numpy/random/np_laplace_op.cc | 21 +++++++++++-------- 2 files changed, 12 insertions(+), 30 deletions(-) diff --git a/python/mxnet/ndarray/numpy/random.py b/python/mxnet/ndarray/numpy/random.py index 39a0a9789278..4e450f9fdacc 100644 --- a/python/mxnet/ndarray/numpy/random.py +++ b/python/mxnet/ndarray/numpy/random.py @@ -1036,27 +1036,6 @@ def laplace(loc=0.0, scale=1.0, size=None, dtype=None, ctx=None, out=None): out : ndarray Drawn samples from the parameterized Laplace distribution. """ - from ...numpy import ndarray as np_ndarray - input_type = (isinstance(loc, np_ndarray), isinstance(scale, np_ndarray)) - if dtype is None: - dtype = 'float32' if ctx is None: ctx = current_context() - if size == (): - size = None - if input_type == (True, True): - return _npi.laplace(loc, scale, loc=None, scale=None, size=size, - ctx=ctx, dtype=dtype, out=out) - elif input_type == (False, True): - return _npi.laplace(scale, loc=loc, scale=None, size=size, - ctx=ctx, dtype=dtype, out=out) - elif input_type == (True, False): - return _npi.laplace(loc, loc=None, scale=scale, size=size, - ctx=ctx, dtype=dtype, out=out) - else: - return _npi.laplace(loc=loc, scale=scale, size=size, - ctx=ctx, dtype=dtype, out=out) - - -def laplace_v2(loc=0.0, scale=1.0, size=None, dtype=None, ctx=None, out=None): return _api_internal.laplace(loc, scale, size, dtype, ctx, out) diff --git a/src/api/operator/numpy/random/np_laplace_op.cc b/src/api/operator/numpy/random/np_laplace_op.cc index f639d2739a5e..b9a64746ebe1 100644 --- a/src/api/operator/numpy/random/np_laplace_op.cc +++ b/src/api/operator/numpy/random/np_laplace_op.cc @@ -35,19 +35,25 @@ MXNET_REGISTER_API("_npi.laplace") nnvm::NodeAttrs attrs; op::NumpyLaplaceParam param; - NDArray* in; + NDArray** inputs = new NDArray*[2](); + int num_inputs = 0; if (args[0].type_code() == kNull) { param.loc = dmlc::nullopt; - } else if (args[0].type_code() == kDLInt) { - param.loc = args[0].operator double(); // convert arg to T } else if (args[0].type_code() == kNDArrayHandle){ param.loc = dmlc::nullopt; - in = args[0].operator mxnet::NDArray *(); + inputs[num_inputs] = args[0].operator mxnet::NDArray *(); + num_inputs++; + } else { + param.loc = args[0].operator double(); // convert arg to T } if (args[1].type_code() == kNull) { param.scale = dmlc::nullopt; + } else if (args[1].type_code() == kNDArrayHandle){ + param.scale = dmlc::nullopt; + inputs[num_inputs] = args[1].operator mxnet::NDArray *(); + num_inputs++; } else { param.scale = args[1].operator double(); // convert arg to T } @@ -74,11 +80,7 @@ MXNET_REGISTER_API("_npi.laplace") attrs.dict["ctx"] = args[3].operator std::string(); } - int num_inputs = 2; - if (param.loc.has_value()) num_inputs -= 1; - if (param.scale.has_value()) num_inputs -= 1; - - NDArray** inputs = in == nullptr ? nullptr : ∈ + inputs = inputs == nullptr ? nullptr : inputs; NDArray* out = args[5].operator mxnet::NDArray*(); NDArray** outputs = out == nullptr ? nullptr : &out; @@ -92,6 +94,7 @@ MXNET_REGISTER_API("_npi.laplace") } else { *ret = ndoutputs[0]; } + delete [] inputs; }); } // namespace mxnet From 4a62caa0679645e176ddc8b604316fd5a4ad8ca5 Mon Sep 17 00:00:00 2001 From: AntiZpvoh Date: Tue, 10 Mar 2020 19:33:56 +0800 Subject: [PATCH 15/22] fix some sanity problems --- src/api/operator/numpy/random/np_laplace_op.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/operator/numpy/random/np_laplace_op.cc b/src/api/operator/numpy/random/np_laplace_op.cc index b9a64746ebe1..fbe05f7103b9 100644 --- a/src/api/operator/numpy/random/np_laplace_op.cc +++ b/src/api/operator/numpy/random/np_laplace_op.cc @@ -40,7 +40,7 @@ MXNET_REGISTER_API("_npi.laplace") if (args[0].type_code() == kNull) { param.loc = dmlc::nullopt; - } else if (args[0].type_code() == kNDArrayHandle){ + } else if (args[0].type_code() == kNDArrayHandle) { param.loc = dmlc::nullopt; inputs[num_inputs] = args[0].operator mxnet::NDArray *(); num_inputs++; @@ -50,7 +50,7 @@ MXNET_REGISTER_API("_npi.laplace") if (args[1].type_code() == kNull) { param.scale = dmlc::nullopt; - } else if (args[1].type_code() == kNDArrayHandle){ + } else if (args[1].type_code() == kNDArrayHandle) { param.scale = dmlc::nullopt; inputs[num_inputs] = args[1].operator mxnet::NDArray *(); num_inputs++; From 20c05c136dae660d064e6a340bfd8859ab760d6d Mon Sep 17 00:00:00 2001 From: AntiZpvoh Date: Tue, 10 Mar 2020 19:35:28 +0800 Subject: [PATCH 16/22] fix some sanity problems --- python/mxnet/ndarray/numpy/random.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/python/mxnet/ndarray/numpy/random.py b/python/mxnet/ndarray/numpy/random.py index 4e450f9fdacc..4497c0c3a4ed 100644 --- a/python/mxnet/ndarray/numpy/random.py +++ b/python/mxnet/ndarray/numpy/random.py @@ -1037,5 +1037,9 @@ def laplace(loc=0.0, scale=1.0, size=None, dtype=None, ctx=None, out=None): Drawn samples from the parameterized Laplace distribution. """ if ctx is None: - ctx = current_context() + ctx = str(current_context()) + else: + ctx = str(ctx) + if dtype is not None and not isinstance(dtype, str): + dtype = np.dtype(dtype).name return _api_internal.laplace(loc, scale, size, dtype, ctx, out) From b52931f90f3622c0a7295047e92f18a8352ad2b6 Mon Sep 17 00:00:00 2001 From: AntiZpvoh Date: Tue, 10 Mar 2020 19:37:56 +0800 Subject: [PATCH 17/22] fix some typos --- src/api/operator/numpy/random/np_laplace_op.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/api/operator/numpy/random/np_laplace_op.cc b/src/api/operator/numpy/random/np_laplace_op.cc index fbe05f7103b9..7f548b81c983 100644 --- a/src/api/operator/numpy/random/np_laplace_op.cc +++ b/src/api/operator/numpy/random/np_laplace_op.cc @@ -68,7 +68,7 @@ MXNET_REGISTER_API("_npi.laplace") } } - if (args[4].type_code() == kNull) { + if (args[3].type_code() == kNull) { param.dtype = mshadow::kFloat32; } else { param.dtype = String2MXNetTypeWithBool(args[4].operator std::string()); @@ -76,8 +76,8 @@ MXNET_REGISTER_API("_npi.laplace") attrs.parsed = std::move(param); attrs.op = op; SetAttrDict(&attrs); - if (args[3].type_code() != kNull) { - attrs.dict["ctx"] = args[3].operator std::string(); + if (args[4].type_code() != kNull) { + attrs.dict["ctx"] = args[4].operator std::string(); } inputs = inputs == nullptr ? nullptr : inputs; From 336cd9f5cde1aa9bf51836d2a8c3cead679679c3 Mon Sep 17 00:00:00 2001 From: AntiZpvoh Date: Tue, 10 Mar 2020 20:34:51 +0800 Subject: [PATCH 18/22] fix some problems --- src/api/operator/numpy/random/np_laplace_op.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/api/operator/numpy/random/np_laplace_op.cc b/src/api/operator/numpy/random/np_laplace_op.cc index 7f548b81c983..394b70c24ac3 100644 --- a/src/api/operator/numpy/random/np_laplace_op.cc +++ b/src/api/operator/numpy/random/np_laplace_op.cc @@ -94,7 +94,6 @@ MXNET_REGISTER_API("_npi.laplace") } else { *ret = ndoutputs[0]; } - delete [] inputs; }); } // namespace mxnet From 1e871ce106b61d7b4444a37d3ecc996c7d119b9a Mon Sep 17 00:00:00 2001 From: AntiZpvoh Date: Wed, 11 Mar 2020 05:47:44 +0000 Subject: [PATCH 19/22] fix a typo --- src/api/operator/numpy/random/np_laplace_op.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/operator/numpy/random/np_laplace_op.cc b/src/api/operator/numpy/random/np_laplace_op.cc index 7f548b81c983..9f3ff227f18a 100644 --- a/src/api/operator/numpy/random/np_laplace_op.cc +++ b/src/api/operator/numpy/random/np_laplace_op.cc @@ -71,7 +71,7 @@ MXNET_REGISTER_API("_npi.laplace") if (args[3].type_code() == kNull) { param.dtype = mshadow::kFloat32; } else { - param.dtype = String2MXNetTypeWithBool(args[4].operator std::string()); + param.dtype = String2MXNetTypeWithBool(args[3].operator std::string()); } attrs.parsed = std::move(param); attrs.op = op; From c115c7306a4f1f92ec3d95538f4a24bff5eb32b7 Mon Sep 17 00:00:00 2001 From: AntiZpvoh Date: Wed, 11 Mar 2020 07:42:08 +0000 Subject: [PATCH 20/22] add size==() condition handling --- python/mxnet/ndarray/numpy/random.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/mxnet/ndarray/numpy/random.py b/python/mxnet/ndarray/numpy/random.py index 4497c0c3a4ed..9fe19a770966 100644 --- a/python/mxnet/ndarray/numpy/random.py +++ b/python/mxnet/ndarray/numpy/random.py @@ -1042,4 +1042,6 @@ def laplace(loc=0.0, scale=1.0, size=None, dtype=None, ctx=None, out=None): ctx = str(ctx) if dtype is not None and not isinstance(dtype, str): dtype = np.dtype(dtype).name + if size == (): + size = None return _api_internal.laplace(loc, scale, size, dtype, ctx, out) From befba1e9c6eac9ef5235f36608d01fddca97fd52 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Fri, 13 Mar 2020 14:36:02 +0000 Subject: [PATCH 21/22] fix some typos --- src/api/operator/numpy/random/np_laplace_op.cc | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/api/operator/numpy/random/np_laplace_op.cc b/src/api/operator/numpy/random/np_laplace_op.cc index e7d724d0c0f6..40e79017c0f2 100644 --- a/src/api/operator/numpy/random/np_laplace_op.cc +++ b/src/api/operator/numpy/random/np_laplace_op.cc @@ -18,8 +18,8 @@ */ /*! - * \file np_init_op.cc - * \brief Implementation of the API of functions in src/operator/numpy/np_init_op.cc + * \file np_laplace_op.cc + * \brief Implementation of the API of functions in src/operator/numpy/np_laplace_op.cc */ #include #include @@ -75,7 +75,7 @@ MXNET_REGISTER_API("_npi.laplace") } attrs.parsed = std::move(param); attrs.op = op; - SetAttrDict(&attrs); + SetAttrDict(&attrs); if (args[4].type_code() != kNull) { attrs.dict["ctx"] = args[4].operator std::string(); } @@ -84,12 +84,9 @@ MXNET_REGISTER_API("_npi.laplace") NDArray* out = args[5].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, num_inputs, inputs, &num_outputs, outputs); if (out) { - // PythonArg(n) designates the nth python argument is to be returned. - // So suppose `out` is the 3rd positional argument, we use PythonArg(2) (0-based index) *ret = PythonArg(5); } else { *ret = ndoutputs[0]; From 5dc7075ef0fb3dc699d711fd2515597042f98d47 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Fri, 13 Mar 2020 14:51:39 +0000 Subject: [PATCH 22/22] remove unused code --- src/operator/numpy/random/np_laplace_op.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/operator/numpy/random/np_laplace_op.h b/src/operator/numpy/random/np_laplace_op.h index 794f50178747..b8e829582c06 100644 --- a/src/operator/numpy/random/np_laplace_op.h +++ b/src/operator/numpy/random/np_laplace_op.h @@ -186,7 +186,6 @@ void NumpyLaplaceForward(const nnvm::NodeAttrs &attrs, &new_lshape, &new_lshape, &new_oshape); int scalar_pos; float scalar_value; - // int type_flag = param.t; if (param.loc.has_value()) { scalar_pos = 0; scalar_value = param.loc.value();