• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2020 Huawei Technologies Co., Ltd
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14# ============================================================================
15"""Operations for random number generators."""
16from mindspore.ops.primitive import constexpr
17from .. import operations as P
18from .. import functional as F
19from .multitype_ops import _constexpr_utils as const_utils
20from ...common import dtype as mstype
21from ...common.seed import _get_graph_seed
22
23
24@constexpr
25def _get_seed(op_seed, kernel_name):
26    "Get the graph-level seed."
27    return _get_graph_seed(op_seed, kernel_name)
28
29
30def normal(shape, mean, stddev, seed=None):
31    """
32    Generates random numbers according to the Normal (or Gaussian) random number distribution.
33
34    Args:
35        shape (tuple): The shape of random tensor to be generated.
36          The format is :math:`(N,*)` where :math:`*` means, any number of additional dimensions.
37        mean (Tensor): The mean μ distribution parameter, which specifies the location of the peak,
38          with data type in [int8, int16, int32, int64, float16, float32].
39        stddev (Tensor): The deviation σ distribution parameter. It should be greater than 0,
40          with data type in [int8, int16, int32, int64, float16, float32].
41        seed (int): Seed is used as entropy source for the Random number engines to generate pseudo-random numbers.
42          must be non-negative. Default: None, which will be treated as 0.
43
44    Returns:
45        Tensor. The shape should be equal to the broadcasted shape between the input `shape` and shapes
46        of `mean` and `stddev`.
47        The dtype is float32.
48
49    Supported Platforms:
50        ``Ascend`` ``GPU`` ``CPU``
51
52    Examples:
53        >>> shape = (3, 1, 2)
54        >>> mean = Tensor(np.array([[3, 4], [5, 6]]), mindspore.float32)
55        >>> stddev = Tensor(1.0, mindspore.float32)
56        >>> output = ops.normal(shape, mean, stddev, seed=5)
57        >>> result = output.shape
58        >>> print(result)
59        (3, 2, 2)
60        >>> shape = (3, 1, 3)
61        >>> mean = Tensor(np.array([[3, 4, 3], [3, 5, 6]]), mindspore.float32)
62        >>> stddev = Tensor(1.0, mindspore.float32)
63        >>> output = ops.normal(shape, mean, stddev, seed=5)
64        >>> result = output.shape
65        >>> print(result)
66        (3, 2, 3)
67        >>> shape = (3, 1, 3)
68        >>> mean = Tensor(np.array([[1, 2, 3], [3, 4, 3], [3, 5, 6]]), mindspore.float32)
69        >>> stddev = Tensor(1.0, mindspore.float32)
70        >>> output = ops.normal(shape, mean, stddev, seed=5)
71        >>> result = output.shape
72        >>> print(result)
73        (3, 3, 3)
74    """
75    mean_dtype = F.dtype(mean)
76    stddev_dtype = F.dtype(stddev)
77    const_utils.check_type_valid(mean_dtype, mstype.int_type + (mstype.float16, mstype.float32), 'normal')
78    const_utils.check_type_valid(stddev_dtype, mstype.int_type + (mstype.float16, mstype.float32), 'normal')
79    seed1, seed2 = _get_seed(seed, "normal")
80    stdnormal = P.StandardNormal(seed1, seed2)
81    random_normal = stdnormal(shape)
82    value = random_normal * stddev + mean
83    return value
84
85
86def laplace(shape, mean, lambda_param, seed=None):
87    r"""
88    Generates random numbers according to the Laplace random number distribution.
89    It is defined as:
90
91    .. math::
92        \text{f}(x;μ,λ) = \frac{1}{2λ}\exp(-\frac{|x-μ|}{λ}),
93
94    Args:
95        shape (tuple): The shape of random tensor to be generated.
96          The format is :math:`(N,*)` where :math:`*` means, any number of additional dimensions.
97        mean (Tensor): The mean μ distribution parameter, which specifies the location of the peak.
98          With float32 data type.
99        lambda_param (Tensor): The parameter used for controlling the variance of this random distribution. The
100          variance of Laplace distribution is equal to twice the square of lambda_param. With float32 data type.
101        seed (int): Seed is used as entropy source for Random number engines generating pseudo-random numbers.
102          Default: None, which will be treated as 0.
103
104    Returns:
105        Tensor. The shape should be the broadcasted shape of input `shape` and shapes of `mean` and `lambda_param`.
106        The dtype is float32.
107
108    Supported Platforms:
109        ``Ascend``
110
111    Examples:
112        >>> import mindspore
113        >>> from mindspore import Tensor
114        >>> from mindspore import ops as ops
115        >>> shape = (2, 3)
116        >>> mean = Tensor(1.0, mindspore.float32)
117        >>> lambda_param = Tensor(1.0, mindspore.float32)
118        >>> output = ops.laplace(shape, mean, lambda_param, seed=5)
119        >>> print(output.shape)
120        (2, 3)
121    """
122    mean_dtype = F.dtype(mean)
123    lambda_param_dtype = F.dtype(lambda_param)
124    const_utils.check_tensors_dtype_same(mean_dtype, mstype.float32, "laplace")
125    const_utils.check_tensors_dtype_same(lambda_param_dtype, mstype.float32, "laplace")
126    seed1, seed2 = _get_seed(seed, "laplace")
127    stdlaplace = P.StandardLaplace(seed1, seed2)
128    rnd = stdlaplace(shape)
129    value = rnd * lambda_param + mean
130    return value
131
132
133def uniform(shape, minval, maxval, seed=None, dtype=mstype.float32):
134    """
135    Generates random numbers according to the Uniform random number distribution.
136
137    Note:
138        The number in tensor minval should be strictly less than maxval at any position after broadcasting.
139
140    Args:
141        shape (tuple): The shape of random tensor to be generated.
142          The format is :math:`(N,*)` where :math:`*` means, any number of additional dimensions
143          and the length of :math:`(N,*)` should be less than 8 in broadcast operation.
144        minval (Tensor): The distribution parameter `a`.
145          It defines the minimum possible generated value, with int32 or float32 data type.
146          If dtype is int32, only one number is allowed.
147        maxval (Tensor): The distribution parameter `b`.
148          It defines the maximum possible generated value, with int32 or float32 data type.
149          If dtype is int32, only one number is allowed.
150        seed (int): Seed is used as entropy source for the random number engines to generate pseudo-random numbers,
151          must be non-negative. Default: None, which will be treated as 0.
152        dtype (mindspore.dtype): Type of the Uniform distribution. If it is int32, it generates numbers from discrete
153          uniform distribution; if it is float32, it generates numbers from continuous uniform distribution. It only
154          supports these two data types. Default: mindspore.float32.
155
156    Returns:
157        Tensor. The shape should be equal to the broadcasted shape between the input `shape` and shapes
158        of `minval` and `maxval`.
159        The dtype is designated as the input `dtype`.
160
161    Raises:
162        TypeError: If `shape` is not tuple.
163        TypeError: If 'minval' or 'maxval' is neither int32 nor float32
164            and dtype of 'minval' is not the same as 'maxval'.
165        TypeError: If `seed` is not an int.
166        TypeError: If 'dtype' is neither int32 nor float32.
167
168    Supported Platforms:
169        ``Ascend`` ``GPU``
170
171    Examples:
172        >>> # For discrete uniform distribution, only one number is allowed for both minval and maxval:
173        >>> shape = (4, 2)
174        >>> minval = Tensor(1, mindspore.int32)
175        >>> maxval = Tensor(2, mindspore.int32)
176        >>> output = ops.uniform(shape, minval, maxval, seed=5, dtype=mindspore.int32)
177        >>>
178        >>> # For continuous uniform distribution, minval and maxval can be multi-dimentional:
179        >>> shape = (3, 1, 2)
180        >>> minval = Tensor(np.array([[3, 4], [5, 6]]), mindspore.float32)
181        >>> maxval = Tensor([8.0, 10.0], mindspore.float32)
182        >>> output = ops.uniform(shape, minval, maxval, seed=5)
183        >>> result = output.shape
184        >>> print(result)
185        (3, 2, 2)
186    """
187    minval_dtype = F.dtype(minval)
188    maxval_dtype = F.dtype(maxval)
189    const_utils.check_type_valid(dtype, [mstype.int32, mstype.float32], 'uniform')
190    const_utils.check_tensors_dtype_same(minval_dtype, dtype, "uniform")
191    const_utils.check_tensors_dtype_same(maxval_dtype, dtype, "uniform")
192    seed1, seed2 = _get_seed(seed, "uniform")
193    if const_utils.is_same_type(dtype, mstype.int32):
194        random_uniform = P.UniformInt(seed1, seed2)
195        value = random_uniform(shape, minval, maxval)
196    else:
197        uniform_real = P.UniformReal(seed1, seed2)
198        random_uniform = uniform_real(shape)
199        value = random_uniform * (maxval - minval) + minval
200    return value
201
202
203def gamma(shape, alpha, beta, seed=None):
204    """
205    Generates random numbers according to the Gamma random number distribution.
206
207    Args:
208        shape (tuple): The shape of random tensor to be generated.
209          The format is :math:`(N,*)` where :math:`*` means, any number of additional dimensions.
210        alpha (Tensor): The alpha α distribution parameter. It should be greater than 0 with float32 data type.
211        beta (Tensor): The beta β distribution parameter. It should be greater than 0 with float32 data type.
212        seed (int): Seed is used as entropy source for the random number engines to generate
213          pseudo-random numbers, must be non-negative. Default: None, which will be treated as 0.
214
215    Returns:
216        Tensor. The shape should be equal to the broadcasted shape between the input `shape` and shapes
217        of `alpha` and `beta`.
218        The dtype is float32.
219
220    Raises:
221        TypeError: If `shape` is not a tuple.
222        TypeError: If neither `alpha` nor `beta` is a Tensor.
223        TypeError: If `seed` is not an int.
224        TypeError: If dtype of `alpha` and `beta` is not float32.
225
226    Supported Platforms:
227        ``Ascend``
228
229    Examples:
230        >>> # case 1: alpha_shape is (2, 2)
231        >>> shape = (3, 1, 2)
232        >>> alpha = Tensor(np.array([[3, 4], [5, 6]]), mindspore.float32)
233        >>> beta = Tensor(np.array([1.0]), mindspore.float32)
234        >>> output = ops.gamma(shape, alpha, beta, seed=5)
235        >>> result = output.shape
236        >>> print(result)
237        (3, 2, 2)
238        >>> # case 2: alpha_shape is (2, 3), so shape is (3, 1, 3)
239        >>> shape = (3, 1, 3)
240        >>> alpha = Tensor(np.array([[1, 3, 4], [2, 5, 6]]), mindspore.float32)
241        >>> beta = Tensor(np.array([1.0]), mindspore.float32)
242        >>> output = ops.gamma(shape, alpha, beta, seed=5)
243        >>> result = output.shape
244        >>> print(result)
245        (3, 2, 3)
246        >>> # case 3: beta_shape is (1, 2), the output is different.
247        >>> shape = (3, 1, 2)
248        >>> alpha = Tensor(np.array([[3, 4], [5, 6]]), mindspore.float32)
249        >>> beta = Tensor(np.array([1.0, 2]), mindspore.float32)
250        >>> output = ops.gamma(shape, alpha, beta, seed=5)
251        >>> result = output.shape
252        >>> print(output)
253        [[[ 2.2132034  5.8855834]]
254         [ 3.3981476  7.5805717]
255        [[ 3.3981476  7.5805717]]
256         [ 3.7190282 19.941492]
257        [[ 2.9512358  2.5969937]]
258         [ 3.786061   5.160872 ]]]
259        >>> # case 4: beta_shape is (2, 1), the output is different.
260        >>> shape = (3, 1, 2)
261        >>> alpha = Tensor(np.array([[3, 4], [5, 6]]), mindspore.float32)
262        >>> beta = Tensor(np.array([[1.0], [2.0]]), mindspore.float32)
263        >>> output = ops.gamma(shape, alpha, beta, seed=5)
264        >>> result = output.shape
265        >>> print(output)
266        [[[ 5.6085486  7.8280783]]
267         [ 15.97684  16.116285]
268        [[ 1.8347423  1.713663]]
269         [ 3.2434065 15.667398]
270        [[ 4.2922077  7.3365674]]
271         [ 5.3876944  13.159832 ]]]
272    """
273    seed1, seed2 = _get_seed(seed, "gamma")
274    random_gamma = P.Gamma(seed1, seed2)
275    value = random_gamma(shape, alpha, beta)
276    return value
277
278
279def poisson(shape, mean, seed=None):
280    r"""
281    Generates random numbers according to the Poisson random number distribution.
282
283    .. math::
284
285        \text{P}(i|μ) = \frac{\exp(-μ)μ^{i}}{i!}
286
287    Args:
288        shape (tuple): The shape of random tensor to be generated.
289          The format is :math:`(N,*)` where :math:`*` means, any number of additional dimensions.
290        mean (Tensor): The mean μ distribution parameter. It should be greater than 0 with float32 data type.
291        seed (int): Seed is used as entropy source for the random number engines to generate pseudo-random numbers
292          and must be non-negative. Default: None, which will be treated as 0.
293
294    Returns:
295        Tensor. The shape should be equal to the broadcasted shape between the input "shape" and shapes of `mean`.
296        The dtype is float32.
297
298    Raises:
299        TypeError: If `shape` is not a tuple.
300        TypeError: If `mean` is not a Tensor whose dtype is not float32.
301        TypeError: If `seed` is not an int.
302
303    Supported Platforms:
304        ``Ascend``
305
306    Examples:
307        >>> # case 1: It can be broadcast.
308        >>> shape = (4, 1)
309        >>> mean = Tensor(np.array([5.0, 10.0]), mindspore.float32)
310        >>> output = ops.poisson(shape, mean, seed=5)
311        >>> result = output.shape
312        >>> print(result)
313        (4, 2)
314        >>> # case 2: It can not be broadcast. It is recommended to use the same shape.
315        >>> shape = (2, 2)
316        >>> mean = Tensor(np.array([[5.0, 10.0], [5.0, 1.0]]), mindspore.float32)
317        >>> output = ops.poisson(shape, mean, seed=5)
318        >>> result = output.shape
319        >>> print(result)
320        (2, 2)
321    """
322    seed1, seed2 = _get_seed(seed, "poisson")
323    random_poisson = P.Poisson(seed1, seed2)
324    value = random_poisson(shape, mean)
325    return value
326
327
328def multinomial(inputs, num_sample, replacement=True, seed=None):
329    r"""
330    Returns a tensor sampled from the multinomial probability distribution located in the corresponding
331    row of the input tensor.
332
333    Note:
334        The rows of input do not need to sum to one (in which case we use the values as weights),
335        but must be non-negative, finite and have a non-zero sum.
336
337    Args:
338        x (Tensor): The input tensor containing probabilities, must be 1 or 2 dimensions, with
339          float32 data type.
340        num_sample (int): Number of samples to draw.
341        replacement (bool, optional): Whether to draw with replacement or not, default True.
342        seed (int, optional): Seed is used as entropy source for the random number engines to generate
343          pseudo-random numbers, must be non-negative. Default: 0.
344
345    Outputs:
346        Tensor, has the same rows with input. The number of sampled indices of each row is `num_samples`.
347        The dtype is float32.
348
349    Raises:
350        TypeError: If `x` is not a Tensor whose dtype is not float32.
351        TypeError: If `num_sample` is not an int.
352        TypeError: If `seed` is neither an int nor a optional.
353
354    Supported Platforms:
355        ``GPU``
356
357    Examples:
358        >>> # case 1: The output is random, and the length of the output is the same as num_sample.
359        >>> x = Tensor([0, 9, 4, 0], mindspore.float32)
360        >>> output = ops.multinomial(x, 2)
361        >>> # print(output)
362        >>> # [1 2] or [2 1]
363        >>> # the case where the result is [2 1] in multiple times.
364        >>> # This is because the value corresponding to the index 1 is larger than the value of the index 2.
365        >>> print(len(output))
366        2
367        >>> # case 2: The output is random, and the length of the output is the same as num_sample.
368        >>> # replacement is False(Default).
369        >>> # If the extracted value is 0, the index value of 1 will be returned.
370        >>> x = Tensor([0, 9, 4, 0], mstype.float32)
371        >>> output = ops.multinomial(x, 4)
372        >>> print(output)
373        [1 1 2 1]
374        >>> # case 3: num_sample == x_length = 4, and replacement is True, Can extract the same elements。
375        >>> x = Tensor([0, 9, 4, 0], mstype.float32)
376        >>> output = ops.multinomial(x, 4, True)
377        >>> print(output)
378        [1 1 2 2]
379    """
380    shape = P.Shape()
381    reshape = P.Reshape()
382    const_utils.check_valid_dim(len(shape(inputs)), "multinomial")
383    seed1, seed2 = _get_seed(seed, "multinomial")
384    if not replacement:
385        if shape(inputs)[-1] < num_sample:
386            const_utils.raise_value_error("For 'multinomial', the 'num_sample' must be less than "
387                                          "the last dimension of input without 'replacement', "
388                                          "but got 'num_sample': {} and "
389                                          "'replacement': {}".format(num_sample, replacement))
390        n_dist = 1
391        if len(shape(inputs)) > 1:
392            n_dist = shape(inputs)[-2]
393        random_uniform = P.UniformReal(seed1, seed2)((n_dist * shape(inputs)[-1],))
394        if n_dist != 1:
395            random_uniform = reshape(random_uniform, (n_dist, shape(inputs)[-1]))
396        vals = P.RealDiv()(P.Log()(random_uniform), inputs + 1e-6)
397        _, indices = P.TopK()(vals, num_sample)
398        return indices
399    return P.Multinomial(seed1, seed2)(inputs, num_sample)
400