Skip to content

Commit 7b5a944

Browse files
stu1130haojin2
authored andcommitted
Numpy compatible multinomial (apache#15219)
* draft of multinomial * rename to more concise name * finish shape * complete the forward function * complete forward without handle 0 dimension & scalar * handle 0 dimension * add new line * fix lint * fix the build error * fix lint * finish unit test * change the registration * make multinomial support pvals as mx.ndarray * delete newline * fix lint error * support input as list, mx.ndarray, np.ndarray & unit test * fix lint * fix the include error * fix lint * refactor & pass the tensor instead of tuple to kernel * fix lint * updata the doc * address the comment
1 parent b0344b0 commit 7b5a944

File tree

7 files changed

+434
-2
lines changed

7 files changed

+434
-2
lines changed

python/mxnet/_numpy_op_doc.py

+30
Original file line numberDiff line numberDiff line change
@@ -109,3 +109,33 @@ def _np_repeat(a, repeats, axis=None):
109109
the given axis.
110110
"""
111111
pass
112+
113+
114+
def _npi_multinomial(a):
115+
"""Draw samples from a multinomial distribution.
116+
117+
The multinomial distribution is a multivariate generalisation of the binomial distribution.
118+
Take an experiment with one of ``p`` possible outcomes. An example of such an experiment is throwing a dice,
119+
where the outcome can be 1 through 6. Each sample drawn from the distribution represents n such experiments.
120+
Its values, ``X_i = [X_0, X_1, ..., X_p]``, represent the number of times the outcome was ``i``.
121+
122+
123+
Parameters
124+
----------
125+
n : int
126+
Number of experiments.
127+
pvals : sequence of floats, length p
128+
Probabilities of each of the p different outcomes. These should sum to 1
129+
(however, the last element is always assumed to account for the remaining
130+
probability, as long as ``sum(pvals[:-1]) <= 1)``.
131+
size : int or tuple of ints, optional
132+
Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` sam-
133+
ples are drawn. Default is None, in which case a single value is returned.
134+
135+
Returns
136+
-------
137+
out : ndarray
138+
The drawn samples, of shape size, if that was provided. If not, the shape is ``(N,)``.
139+
In other words, each entry ``out[i,j,...,:]`` is an N-dimensional value drawn from the distribution.
140+
"""
141+
pass

python/mxnet/ndarray/numpy/random.py

+40-1
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@
1717

1818
"""Namespace for operators used in Gluon dispatched by F=ndarray."""
1919
from __future__ import absolute_import
20+
import numpy as np
2021
from ...base import numeric_types
2122
from ...context import current_context
23+
from ..ndarray import NDArray
2224
from . import _internal as _npi
2325

24-
__all__ = ['uniform', 'normal']
26+
__all__ = ['uniform', 'normal', 'multinomial']
2527

2628

2729
def _random_helper(random, sampler, params, shape, dtype, ctx, out, kwargs):
@@ -135,3 +137,40 @@ def normal(loc=0.0, scale=1.0, size=None, **kwargs):
135137
out = kwargs.pop('out', None)
136138
return _random_helper(_npi.random_normal, None,
137139
[loc, scale], size, dtype, ctx, out, kwargs)
140+
141+
142+
def multinomial(n, pvals, size=None):
143+
"""Draw samples from a multinomial distribution.
144+
145+
The multinomial distribution is a multivariate generalisation of the binomial distribution.
146+
Take an experiment with one of ``p`` possible outcomes. An example of such an experiment is throwing a dice,
147+
where the outcome can be 1 through 6. Each sample drawn from the distribution represents n such experiments.
148+
Its values, ``X_i = [X_0, X_1, ..., X_p]``, represent the number of times the outcome was ``i``.
149+
150+
151+
Parameters
152+
----------
153+
n : int
154+
Number of experiments.
155+
pvals : sequence of floats, length p
156+
Probabilities of each of the p different outcomes. These should sum to 1
157+
(however, the last element is always assumed to account for the remaining
158+
probability, as long as ``sum(pvals[:-1]) <= 1)``.
159+
size : int or tuple of ints, optional
160+
Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` sam-
161+
ples are drawn. Default is None, in which case a single value is returned.
162+
163+
Returns
164+
-------
165+
out : ndarray
166+
The drawn samples, of shape size, if that was provided. If not, the shape is ``(N,)``.
167+
In other words, each entry ``out[i,j,...,:]`` is an N-dimensional value drawn from the distribution.
168+
"""
169+
if isinstance(pvals, NDArray):
170+
return _npi.multinomial(pvals, pvals=None, n=n, size=size)
171+
else:
172+
if isinstance(pvals, np.ndarray):
173+
pvals = pvals.tolist()
174+
if any(isinstance(i, list) for i in pvals):
175+
raise ValueError('object too deep for desired array')
176+
return _npi.multinomial(n=n, pvals=pvals, size=size)

python/mxnet/numpy/random.py

+30
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,33 @@ def normal(loc=0.0, scale=1.0, size=None, **kwargs):
9898
This function currently does not support ``loc`` and ``scale`` as ndarrays.
9999
"""
100100
return _mx_nd_np.random.normal(loc, scale, size, **kwargs)
101+
102+
103+
def multinomial(n, pvals, size=None, **kwargs):
104+
"""Draw samples from a multinomial distribution.
105+
106+
The multinomial distribution is a multivariate generalisation of the binomial distribution.
107+
Take an experiment with one of ``p`` possible outcomes. An example of such an experiment is throwing a dice,
108+
where the outcome can be 1 through 6. Each sample drawn from the distribution represents n such experiments.
109+
Its values, ``X_i = [X_0, X_1, ..., X_p]``, represent the number of times the outcome was ``i``.
110+
111+
112+
Parameters
113+
----------
114+
n : int
115+
Number of experiments.
116+
pvals : sequence of floats, length p
117+
Probabilities of each of the p different outcomes. These should sum to 1
118+
(however, the last element is always assumed to account for the remaining
119+
probability, as long as ``sum(pvals[:-1]) <= 1)``.
120+
size : int or tuple of ints, optional
121+
Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` sam-
122+
ples are drawn. Default is None, in which case a single value is returned.
123+
124+
Returns
125+
-------
126+
out : ndarray
127+
The drawn samples, of shape size, if that was provided. If not, the shape is ``(N,)``.
128+
In other words, each entry ``out[i,j,...,:]`` is an N-dimensional value drawn from the distribution.
129+
"""
130+
return _mx_nd_np.random.multinomial(n, pvals, size, **kwargs)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
/*!
21+
* Copyright (c) 2019 by Contributors
22+
* \file np_multinomial_op.h
23+
* \brief Operator for numpy sampling from multinomial distributions
24+
*/
25+
#include "./np_multinomial_op.h"
26+
27+
namespace mxnet {
28+
namespace op {
29+
30+
DMLC_REGISTER_PARAMETER(NumpyMultinomialParam);
31+
32+
NNVM_REGISTER_OP(_npi_multinomial)
33+
.describe(R"code(Draw samples from a multinomial distribution. "
34+
"The multinomial distribution is a multivariate generalisation of the binomial distribution. "
35+
"Take an experiment with one of p possible outcomes. "
36+
"An example of such an experiment is throwing a dice, where the outcome can be 1 through 6. "
37+
"Each sample drawn from the distribution represents n such experiments. "
38+
"Its values, X_i = [X_0, X_1, ..., X_p], represent the number of times the outcome was i.
39+
)code")
40+
.set_num_inputs(
41+
[](const nnvm::NodeAttrs& attrs) {
42+
const NumpyMultinomialParam& param = nnvm::get<NumpyMultinomialParam>(attrs.parsed);
43+
return param.pvals.has_value() ? 0U : 1U;
44+
}
45+
)
46+
.set_num_outputs(1)
47+
.set_attr_parser(ParamParser<NumpyMultinomialParam>)
48+
.set_attr<mxnet::FInferShape>("FInferShape", NumpyMultinomialOpShape)
49+
.set_attr<nnvm::FInferType>("FInferType", NumpyMultinomialOpType)
50+
.set_attr<FResourceRequest>("FResourceRequest",
51+
[](const nnvm::NodeAttrs& attrs) {
52+
return std::vector<ResourceRequest>{
53+
ResourceRequest::kRandom, ResourceRequest::kTempSpace};
54+
})
55+
.set_attr<FCompute>("FCompute<cpu>", NumpyMultinomialForward<cpu>)
56+
.set_attr<nnvm::FGradient>("FGradient", MakeZeroGradNodes)
57+
.add_argument("a", "NDArray-or-Symbol", "Source input")
58+
.add_arguments(NumpyMultinomialParam::__FIELDS__());
59+
60+
} // namespace op
61+
} // namespace mxnet
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
/*!
21+
* Copyright (c) 2019 by Contributors
22+
* \file np_multinomial_op.cu
23+
* \brief Operator for numpy sampling from multinomial distributions
24+
*/
25+
#include "./np_multinomial_op.h"
26+
27+
namespace mxnet {
28+
namespace op {
29+
30+
NNVM_REGISTER_OP(_npi_multinomial)
31+
.set_attr<FCompute>("FCompute<gpu>", NumpyMultinomialForward<gpu>);
32+
33+
} // namespace op
34+
} // namespace mxnet

0 commit comments

Comments
 (0)