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