• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2015 The TensorFlow Authors. All Rights Reserved.
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 generating random numbers."""
16
17import numpy as np
18
19from tensorflow.python.eager import context
20from tensorflow.python.framework import dtypes
21from tensorflow.python.framework import ops
22from tensorflow.python.framework import random_seed
23from tensorflow.python.framework import tensor_util
24from tensorflow.python.ops import array_ops
25from tensorflow.python.ops import control_flow_ops
26from tensorflow.python.ops import gen_random_ops
27from tensorflow.python.ops import math_ops
28from tensorflow.python.ops import stateless_random_ops
29
30# go/tf-wildcard-import
31# pylint: disable=wildcard-import
32from tensorflow.python.ops.gen_random_ops import *
33# pylint: enable=wildcard-import
34
35from tensorflow.python.util import deprecation
36from tensorflow.python.util import dispatch
37from tensorflow.python.util.tf_export import tf_export
38
39
40@tf_export("random.normal", v1=["random.normal", "random_normal"])
41@dispatch.add_dispatch_support
42@deprecation.deprecated_endpoints("random_normal")
43def random_normal(shape,
44                  mean=0.0,
45                  stddev=1.0,
46                  dtype=dtypes.float32,
47                  seed=None,
48                  name=None):
49  """Outputs random values from a normal distribution.
50
51  Example that generates a new set of random values every time:
52
53  >>> tf.random.set_seed(5);
54  >>> tf.random.normal([4], 0, 1, tf.float32)
55  <tf.Tensor: shape=(4,), dtype=float32, numpy=..., dtype=float32)>
56
57  Example that outputs a reproducible result:
58
59  >>> tf.random.set_seed(5);
60  >>> tf.random.normal([2,2], 0, 1, tf.float32, seed=1)
61  <tf.Tensor: shape=(2, 2), dtype=float32, numpy=
62  array([[-1.3768897 , -0.01258316],
63        [-0.169515   ,  1.0824056 ]], dtype=float32)>
64
65  In this case, we are setting both the global and operation-level seed to
66  ensure this result is reproducible.  See `tf.random.set_seed` for more
67  information.
68
69  Args:
70    shape: A 1-D integer Tensor or Python array. The shape of the output tensor.
71    mean: A Tensor or Python value of type `dtype`, broadcastable with `stddev`.
72      The mean of the normal distribution.
73    stddev: A Tensor or Python value of type `dtype`, broadcastable with `mean`.
74      The standard deviation of the normal distribution.
75    dtype: The float type of the output: `float16`, `bfloat16`, `float32`,
76      `float64`. Defaults to `float32`.
77    seed: A Python integer. Used to create a random seed for the distribution.
78      See
79      `tf.random.set_seed`
80      for behavior.
81    name: A name for the operation (optional).
82
83  Returns:
84    A tensor of the specified shape filled with random normal values.
85  """
86  with ops.name_scope(name, "random_normal", [shape, mean, stddev]) as name:
87    shape_tensor = tensor_util.shape_tensor(shape)
88    mean_tensor = ops.convert_to_tensor(mean, dtype=dtype, name="mean")
89    stddev_tensor = ops.convert_to_tensor(stddev, dtype=dtype, name="stddev")
90    seed1, seed2 = random_seed.get_seed(seed)
91    rnd = gen_random_ops.random_standard_normal(
92        shape_tensor, dtype, seed=seed1, seed2=seed2)
93    mul = rnd * stddev_tensor
94    value = math_ops.add(mul, mean_tensor, name=name)
95    tensor_util.maybe_set_static_shape(value, shape)
96    return value
97
98
99ops.NotDifferentiable("RandomStandardNormal")
100
101
102def parameterized_truncated_normal(shape,
103                                   means=0.0,
104                                   stddevs=1.0,
105                                   minvals=-2.0,
106                                   maxvals=2.0,
107                                   dtype=dtypes.float32,
108                                   seed=None,
109                                   name=None):
110  """Outputs random values from a truncated normal distribution.
111
112  The generated values follow a normal distribution with specified mean and
113  standard deviation, except that values whose magnitude is more than 2 standard
114  deviations from the mean are dropped and re-picked.
115
116  Args:
117    shape: A 1-D integer Tensor or Python array. The shape of the output tensor.
118    means: A 0-D Tensor or Python value of type `dtype`. The mean of the
119      truncated normal distribution.
120    stddevs: A 0-D Tensor or Python value of type `dtype`. The standard
121      deviation of the truncated normal distribution.
122    minvals: A 0-D Tensor or Python value of type `dtype`. The minimum value of
123      the truncated normal distribution.
124    maxvals: A 0-D Tensor or Python value of type `dtype`. The maximum value of
125      the truncated normal distribution.
126    dtype: The type of the output.
127    seed: A Python integer. Used to create a random seed for the distribution.
128      See
129      `tf.random.set_seed`
130      for behavior.
131    name: A name for the operation (optional).
132
133  Returns:
134    A tensor of the specified shape filled with random truncated normal values.
135  """
136  with ops.name_scope(name, "parameterized_truncated_normal",
137                      [shape, means, stddevs, minvals, maxvals]) as name:
138    shape_tensor = tensor_util.shape_tensor(shape)
139    means_tensor = ops.convert_to_tensor(means, dtype=dtype, name="means")
140    stddevs_tensor = ops.convert_to_tensor(stddevs, dtype=dtype, name="stddevs")
141    minvals_tensor = ops.convert_to_tensor(minvals, dtype=dtype, name="minvals")
142    maxvals_tensor = ops.convert_to_tensor(maxvals, dtype=dtype, name="maxvals")
143    seed1, seed2 = random_seed.get_seed(seed)
144    rnd = gen_random_ops.parameterized_truncated_normal(
145        shape_tensor,
146        means_tensor,
147        stddevs_tensor,
148        minvals_tensor,
149        maxvals_tensor,
150        seed=seed1,
151        seed2=seed2)
152    tensor_util.maybe_set_static_shape(rnd, shape)
153    return rnd
154
155
156@tf_export("random.truncated_normal",
157           v1=["random.truncated_normal", "truncated_normal"])
158@dispatch.add_dispatch_support
159@deprecation.deprecated_endpoints("truncated_normal")
160def truncated_normal(shape,
161                     mean=0.0,
162                     stddev=1.0,
163                     dtype=dtypes.float32,
164                     seed=None,
165                     name=None):
166  """Outputs random values from a truncated normal distribution.
167
168  The values are drawn from a normal distribution with specified mean and
169  standard deviation, discarding and re-drawing any samples that are more than
170  two standard deviations from the mean.
171
172  Examples:
173
174  >>> tf.random.truncated_normal(shape=[2])
175  <tf.Tensor: shape=(2,), dtype=float32, numpy=array([..., ...], dtype=float32)>
176
177  >>> tf.random.truncated_normal(shape=[2], mean=3, stddev=1, dtype=tf.float32)
178  <tf.Tensor: shape=(2,), dtype=float32, numpy=array([..., ...], dtype=float32)>
179
180  Args:
181    shape: A 1-D integer Tensor or Python array. The shape of the output tensor.
182    mean: A 0-D Tensor or Python value of type `dtype`. The mean of the
183      truncated normal distribution.
184    stddev: A 0-D Tensor or Python value of type `dtype`. The standard deviation
185      of the normal distribution, before truncation.
186    dtype: The type of the output. Restricted to floating-point types:
187      `tf.half`, `tf.float`, `tf.double`, etc.
188    seed: A Python integer. Used to create a random seed for the distribution.
189      See `tf.random.set_seed` for more information.
190    name: A name for the operation (optional).
191
192  Returns:
193    A tensor of the specified shape filled with random truncated normal values.
194  """
195  with ops.name_scope(name, "truncated_normal", [shape, mean, stddev]) as name:
196    shape_tensor = tensor_util.shape_tensor(shape)
197    mean_tensor = ops.convert_to_tensor(mean, dtype=dtype, name="mean")
198    stddev_tensor = ops.convert_to_tensor(stddev, dtype=dtype, name="stddev")
199    seed1, seed2 = random_seed.get_seed(seed)
200    rnd = gen_random_ops.truncated_normal(
201        shape_tensor, dtype, seed=seed1, seed2=seed2)
202    mul = rnd * stddev_tensor
203    value = math_ops.add(mul, mean_tensor, name=name)
204    tensor_util.maybe_set_static_shape(value, shape)
205    return value
206
207
208ops.NotDifferentiable("ParameterizedTruncatedNormal")
209ops.NotDifferentiable("TruncatedNormal")
210
211
212@tf_export("random.uniform", v1=["random.uniform", "random_uniform"])
213@dispatch.add_dispatch_support
214@deprecation.deprecated_endpoints("random_uniform")
215def random_uniform(shape,
216                   minval=0,
217                   maxval=None,
218                   dtype=dtypes.float32,
219                   seed=None,
220                   name=None):
221  """Outputs random values from a uniform distribution.
222
223  The generated values follow a uniform distribution in the range
224  `[minval, maxval)`. The lower bound `minval` is included in the range, while
225  the upper bound `maxval` is excluded.
226
227  For floats, the default range is `[0, 1)`.  For ints, at least `maxval` must
228  be specified explicitly.
229
230  In the integer case, the random integers are slightly biased unless
231  `maxval - minval` is an exact power of two.  The bias is small for values of
232  `maxval - minval` significantly smaller than the range of the output (either
233  `2**32` or `2**64`).
234
235  Examples:
236
237  >>> tf.random.uniform(shape=[2])
238  <tf.Tensor: shape=(2,), dtype=float32, numpy=array([..., ...], dtype=float32)>
239  >>> tf.random.uniform(shape=[], minval=-1., maxval=0.)
240  <tf.Tensor: shape=(), dtype=float32, numpy=-...>
241  >>> tf.random.uniform(shape=[], minval=5, maxval=10, dtype=tf.int64)
242  <tf.Tensor: shape=(), dtype=int64, numpy=...>
243
244  The `seed` argument produces a deterministic sequence of tensors across
245  multiple calls. To repeat that sequence, use `tf.random.set_seed`:
246
247  >>> tf.random.set_seed(5)
248  >>> tf.random.uniform(shape=[], maxval=3, dtype=tf.int32, seed=10)
249  <tf.Tensor: shape=(), dtype=int32, numpy=2>
250  >>> tf.random.uniform(shape=[], maxval=3, dtype=tf.int32, seed=10)
251  <tf.Tensor: shape=(), dtype=int32, numpy=0>
252  >>> tf.random.set_seed(5)
253  >>> tf.random.uniform(shape=[], maxval=3, dtype=tf.int32, seed=10)
254  <tf.Tensor: shape=(), dtype=int32, numpy=2>
255  >>> tf.random.uniform(shape=[], maxval=3, dtype=tf.int32, seed=10)
256  <tf.Tensor: shape=(), dtype=int32, numpy=0>
257
258  Without `tf.random.set_seed` but with a `seed` argument is specified, small
259  changes to function graphs or previously executed operations will change the
260  returned value. See `tf.random.set_seed` for details.
261
262  Args:
263    shape: A 1-D integer Tensor or Python array. The shape of the output tensor.
264    minval: A Tensor or Python value of type `dtype`, broadcastable with
265      `shape` (for integer types, broadcasting is not supported, so it needs to
266      be a scalar). The lower bound on the range of random values to generate
267      (inclusive).  Defaults to 0.
268    maxval: A Tensor or Python value of type `dtype`, broadcastable with
269      `shape` (for integer types, broadcasting is not supported, so it needs to
270      be a scalar). The upper bound on the range of random values to generate
271      (exclusive). Defaults to 1 if `dtype` is floating point.
272    dtype: The type of the output: `float16`, `bfloat16`, `float32`, `float64`,
273      `int32`, or `int64`. Defaults to `float32`.
274    seed: A Python integer. Used in combination with `tf.random.set_seed` to
275      create a reproducible sequence of tensors across multiple calls.
276    name: A name for the operation (optional).
277
278  Returns:
279    A tensor of the specified shape filled with random uniform values.
280
281  Raises:
282    ValueError: If `dtype` is integral and `maxval` is not specified.
283  """
284  dtype = dtypes.as_dtype(dtype)
285  accepted_dtypes = (dtypes.float16, dtypes.bfloat16, dtypes.float32,
286                     dtypes.float64, dtypes.int32, dtypes.int64)
287  if dtype not in accepted_dtypes:
288    raise ValueError(
289        f"Argument `dtype` got invalid value {dtype}. Accepted dtypes are "
290        f"{accepted_dtypes}.")
291  if maxval is None:
292    if dtype.is_integer:
293      raise ValueError("Must specify maxval for integer dtype %r" % dtype)
294    maxval = 1
295  with ops.name_scope(name, "random_uniform", [shape, minval, maxval]) as name:
296    shape = tensor_util.shape_tensor(shape)
297    # In case of [0,1) floating results, minval and maxval is unused. We do an
298    # `is` comparison here since this is cheaper than isinstance or  __eq__.
299    minval_is_zero = isinstance(minval, int) and minval == 0
300    maxval_is_one = isinstance(maxval, int) and maxval == 1
301    if not minval_is_zero or not maxval_is_one or dtype.is_integer:
302      minval = ops.convert_to_tensor(minval, dtype=dtype, name="min")
303      maxval = ops.convert_to_tensor(maxval, dtype=dtype, name="max")
304    seed1, seed2 = random_seed.get_seed(seed)
305    if dtype.is_integer:
306      result = gen_random_ops.random_uniform_int(
307          shape, minval, maxval, seed=seed1, seed2=seed2, name=name)
308    else:
309      result = gen_random_ops.random_uniform(
310          shape, dtype, seed=seed1, seed2=seed2)
311      if minval_is_zero:
312        if not maxval_is_one:
313          result = math_ops.multiply(result, maxval)
314      else:
315        result = math_ops.add(result * (maxval - minval), minval, name=name)
316    # TODO(b/132092188): C++ shape inference inside functional ops does not
317    # cross FuncGraph boundaries since that information is only available in
318    # python. So we manually get the static shape using
319    # `constant_value_as_shape` which *does* cross function boundaries.
320    tensor_util.maybe_set_static_shape(result, shape)
321    return result
322
323
324ops.NotDifferentiable("RandomUniform")
325
326
327@tf_export("random.shuffle", v1=["random.shuffle", "random_shuffle"])
328@dispatch.add_dispatch_support
329@deprecation.deprecated_endpoints("random_shuffle")
330def random_shuffle(value, seed=None, name=None):
331  """Randomly shuffles a tensor along its first dimension.
332
333  The tensor is shuffled along dimension 0, such that each `value[j]` is mapped
334  to one and only one `output[i]`. For example, a mapping that might occur for a
335  3x2 tensor is:
336
337  ```python
338  [[1, 2],       [[5, 6],
339   [3, 4],  ==>   [1, 2],
340   [5, 6]]        [3, 4]]
341  ```
342
343  Args:
344    value: A Tensor to be shuffled.
345    seed: A Python integer. Used to create a random seed for the distribution.
346      See
347      `tf.random.set_seed`
348      for behavior.
349    name: A name for the operation (optional).
350
351  Returns:
352    A tensor of same shape and type as `value`, shuffled along its first
353    dimension.
354  """
355  seed1, seed2 = random_seed.get_seed(seed)
356  return gen_random_ops.random_shuffle(
357      value, seed=seed1, seed2=seed2, name=name)
358
359
360ops.NotDifferentiable("RandomShuffle")
361
362
363@tf_export("image.random_crop", v1=["image.random_crop", "random_crop"])
364@dispatch.add_dispatch_support
365@deprecation.deprecated_endpoints("random_crop")
366def random_crop(value, size, seed=None, name=None):
367  """Randomly crops a tensor to a given size.
368
369  Slices a shape `size` portion out of `value` at a uniformly chosen offset.
370  Requires `value.shape >= size`.
371
372  If a dimension should not be cropped, pass the full size of that dimension.
373  For example, RGB images can be cropped with
374  `size = [crop_height, crop_width, 3]`.
375
376  Example usage:
377
378  >>> image = [[1, 2, 3], [4, 5, 6]]
379  >>> result = tf.image.random_crop(value=image, size=(1, 3))
380  >>> result.shape.as_list()
381  [1, 3]
382
383  For producing deterministic results given a `seed` value, use
384  `tf.image.stateless_random_crop`. Unlike using the `seed` param with
385  `tf.image.random_*` ops, `tf.image.stateless_random_*` ops guarantee the same
386  results given the same seed independent of how many times the function is
387  called, and independent of global seed settings (e.g. tf.random.set_seed).
388
389  Args:
390    value: Input tensor to crop.
391    size: 1-D tensor with size the rank of `value`.
392    seed: Python integer. Used to create a random seed. See
393      `tf.random.set_seed`
394      for behavior.
395    name: A name for this operation (optional).
396
397  Returns:
398    A cropped tensor of the same rank as `value` and shape `size`.
399  """
400  with ops.name_scope(name, "random_crop", [value, size]) as name:
401    value = ops.convert_to_tensor(value, name="value")
402    size = ops.convert_to_tensor(size, dtype=dtypes.int32, name="size")
403    shape = array_ops.shape(value)
404    check = control_flow_ops.Assert(
405        math_ops.reduce_all(shape >= size),
406        ["Need value.shape >= size, got ", shape, size],
407        summarize=1000)
408    shape = control_flow_ops.with_dependencies([check], shape)
409    limit = shape - size + 1
410    offset = random_uniform(
411        array_ops.shape(shape),
412        dtype=size.dtype,
413        maxval=size.dtype.max,
414        seed=seed) % limit
415    return array_ops.slice(value, offset, size, name=name)
416
417
418@tf_export("image.stateless_random_crop", v1=[])
419@dispatch.add_dispatch_support
420def stateless_random_crop(value, size, seed, name=None):
421  """Randomly crops a tensor to a given size in a deterministic manner.
422
423  Slices a shape `size` portion out of `value` at a uniformly chosen offset.
424  Requires `value.shape >= size`.
425
426  If a dimension should not be cropped, pass the full size of that dimension.
427  For example, RGB images can be cropped with
428  `size = [crop_height, crop_width, 3]`.
429
430  Guarantees the same results given the same `seed` independent of how many
431  times the function is called, and independent of global seed settings (e.g.
432  `tf.random.set_seed`).
433
434  Usage Example:
435
436  >>> image = [[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]]
437  >>> seed = (1, 2)
438  >>> tf.image.stateless_random_crop(value=image, size=(1, 2, 3), seed=seed)
439  <tf.Tensor: shape=(1, 2, 3), dtype=int32, numpy=
440  array([[[1, 2, 3],
441          [4, 5, 6]]], dtype=int32)>
442
443  Args:
444    value: Input tensor to crop.
445    size: 1-D tensor with size the rank of `value`.
446    seed: A shape [2] Tensor, the seed to the random number generator. Must have
447      dtype `int32` or `int64`. (When using XLA, only `int32` is allowed.)
448    name: A name for this operation (optional).
449
450  Returns:
451    A cropped tensor of the same rank as `value` and shape `size`.
452  """
453  with ops.name_scope(name, "random_crop", [value, size]) as name:
454    value = ops.convert_to_tensor(value, name="value")
455    size = ops.convert_to_tensor(size, dtype=dtypes.int32, name="size")
456    shape = array_ops.shape(value)
457    check = control_flow_ops.Assert(
458        math_ops.reduce_all(shape >= size),
459        ["Need value.shape >= size, got ", shape, size],
460        summarize=1000)
461    shape = control_flow_ops.with_dependencies([check], shape)
462    limit = shape - size + 1
463    offset = stateless_random_ops.stateless_random_uniform(
464        array_ops.shape(shape),
465        dtype=size.dtype,
466        maxval=size.dtype.max,
467        seed=seed) % limit
468    return array_ops.slice(value, offset, size, name=name)
469
470
471@tf_export(v1=["random.multinomial", "multinomial"])
472@dispatch.add_dispatch_support
473@deprecation.deprecated(
474    date=None, instructions="Use `tf.random.categorical` instead.")
475def multinomial(logits, num_samples, seed=None, name=None, output_dtype=None):
476  """Draws samples from a multinomial distribution.
477
478  Example:
479
480  ```python
481  # samples has shape [1, 5], where each value is either 0 or 1 with equal
482  # probability.
483  samples = tf.random.categorical(tf.math.log([[0.5, 0.5]]), 5)
484  ```
485
486  Args:
487    logits: 2-D Tensor with shape `[batch_size, num_classes]`.  Each slice
488      `[i, :]` represents the unnormalized log-probabilities for all classes.
489    num_samples: 0-D.  Number of independent samples to draw for each row slice.
490    seed: A Python integer. Used to create a random seed for the distribution.
491      See `tf.random.set_seed` for behavior.
492    name: Optional name for the operation.
493    output_dtype: The integer type of the output: `int32` or `int64`. Defaults
494      to `int64`.
495
496  Returns:
497    The drawn samples of shape `[batch_size, num_samples]`.
498  """
499  with ops.name_scope(name, "multinomial", [logits]):
500    return multinomial_categorical_impl(logits, num_samples, output_dtype, seed)
501
502
503@tf_export("random.categorical")
504@dispatch.add_dispatch_support
505def categorical(logits, num_samples, dtype=None, seed=None, name=None):
506  """Draws samples from a categorical distribution.
507
508  Example:
509
510  ```python
511  # samples has shape [1, 5], where each value is either 0 or 1 with equal
512  # probability.
513  samples = tf.random.categorical(tf.math.log([[0.5, 0.5]]), 5)
514  ```
515
516  Args:
517    logits: 2-D Tensor with shape `[batch_size, num_classes]`.  Each slice
518      `[i, :]` represents the unnormalized log-probabilities for all classes.
519    num_samples: 0-D.  Number of independent samples to draw for each row slice.
520    dtype: The integer type of the output: `int32` or `int64`. Defaults to
521      `int64`.
522    seed: A Python integer. Used to create a random seed for the distribution.
523      See `tf.random.set_seed` for behavior.
524    name: Optional name for the operation.
525
526  Returns:
527    The drawn samples of shape `[batch_size, num_samples]`.
528  """
529  with ops.name_scope(name, "categorical", [logits]):
530    return multinomial_categorical_impl(logits, num_samples, dtype, seed)
531
532
533def multinomial_categorical_impl(logits, num_samples, dtype, seed):
534  """Implementation for random.categorical (v1) and random.categorical (v2)."""
535  logits = ops.convert_to_tensor(logits, name="logits")
536  dtype = dtypes.as_dtype(dtype) if dtype else dtypes.int64
537  accepted_dtypes = (dtypes.int32, dtypes.int64)
538  if dtype not in accepted_dtypes:
539    raise ValueError(
540        f"Argument `dtype` got invalid value {dtype}. Accepted dtypes are "
541        f"{accepted_dtypes}.")
542  seed1, seed2 = random_seed.get_seed(seed)
543  return gen_random_ops.multinomial(
544      logits, num_samples, seed=seed1, seed2=seed2, output_dtype=dtype)
545
546
547ops.NotDifferentiable("Multinomial")
548
549
550def _maybe_set_static_shape_helper(tensor, shape, postfix_tensor):
551  if (not context.executing_eagerly() and
552      ops.get_default_graph().building_function and
553      not tensor.shape.is_fully_defined()):
554    shape = tensor_util.shape_tensor(shape)
555    const_shape = tensor_util.constant_value_as_shape(shape)
556    postfix_tensor = ops.convert_to_tensor(postfix_tensor)
557    tensor.set_shape(const_shape.concatenate(postfix_tensor.shape))
558
559
560@tf_export("random.gamma", v1=["random.gamma", "random_gamma"])
561@dispatch.add_dispatch_support
562@deprecation.deprecated_endpoints("random_gamma")
563def random_gamma(shape,
564                 alpha,
565                 beta=None,
566                 dtype=dtypes.float32,
567                 seed=None,
568                 name=None):
569  """Draws `shape` samples from each of the given Gamma distribution(s).
570
571  `alpha` is the shape parameter describing the distribution(s), and `beta` is
572  the inverse scale parameter(s).
573
574  Note: Because internal calculations are done using `float64` and casting has
575  `floor` semantics, we must manually map zero outcomes to the smallest
576  possible positive floating-point value, i.e., `np.finfo(dtype).tiny`.  This
577  means that `np.finfo(dtype).tiny` occurs more frequently than it otherwise
578  should.  This bias can only happen for small values of `alpha`, i.e.,
579  `alpha << 1` or large values of `beta`, i.e., `beta >> 1`.
580
581  The samples are differentiable w.r.t. alpha and beta.
582  The derivatives are computed using the approach described in
583  (Figurnov et al., 2018).
584
585  Example:
586
587  ```python
588  samples = tf.random.gamma([10], [0.5, 1.5])
589  # samples has shape [10, 2], where each slice [:, 0] and [:, 1] represents
590  # the samples drawn from each distribution
591
592  samples = tf.random.gamma([7, 5], [0.5, 1.5])
593  # samples has shape [7, 5, 2], where each slice [:, :, 0] and [:, :, 1]
594  # represents the 7x5 samples drawn from each of the two distributions
595
596  alpha = tf.constant([[1.],[3.],[5.]])
597  beta = tf.constant([[3., 4.]])
598  samples = tf.random.gamma([30], alpha=alpha, beta=beta)
599  # samples has shape [30, 3, 2], with 30 samples each of 3x2 distributions.
600
601  loss = tf.reduce_mean(tf.square(samples))
602  dloss_dalpha, dloss_dbeta = tf.gradients(loss, [alpha, beta])
603  # unbiased stochastic derivatives of the loss function
604  alpha.shape == dloss_dalpha.shape  # True
605  beta.shape == dloss_dbeta.shape  # True
606  ```
607
608  Args:
609    shape: A 1-D integer Tensor or Python array. The shape of the output samples
610      to be drawn per alpha/beta-parameterized distribution.
611    alpha: A Tensor or Python value or N-D array of type `dtype`. `alpha`
612      provides the shape parameter(s) describing the gamma distribution(s) to
613      sample. Must be broadcastable with `beta`.
614    beta: A Tensor or Python value or N-D array of type `dtype`. Defaults to 1.
615      `beta` provides the inverse scale parameter(s) of the gamma
616      distribution(s) to sample. Must be broadcastable with `alpha`.
617    dtype: The type of alpha, beta, and the output: `float16`, `float32`, or
618      `float64`.
619    seed: A Python integer. Used to create a random seed for the distributions.
620      See
621      `tf.random.set_seed`
622      for behavior.
623    name: Optional name for the operation.
624
625  Returns:
626    samples: a `Tensor` of shape
627      `tf.concat([shape, tf.shape(alpha + beta)], axis=0)` with values of type
628      `dtype`.
629
630  References:
631    Implicit Reparameterization Gradients:
632      [Figurnov et al., 2018]
633      (http://papers.nips.cc/paper/7326-implicit-reparameterization-gradients)
634      ([pdf]
635      (http://papers.nips.cc/paper/7326-implicit-reparameterization-gradients.pdf))
636  """
637  with ops.name_scope(name, "random_gamma", [shape, alpha, beta]):
638    shape = ops.convert_to_tensor(shape, name="shape", dtype=dtypes.int32)
639    alpha = ops.convert_to_tensor(alpha, name="alpha", dtype=dtype)
640    beta = ops.convert_to_tensor(
641        beta if beta is not None else 1, name="beta", dtype=dtype)
642    broadcast_shape = array_ops.broadcast_dynamic_shape(
643        array_ops.shape(alpha), array_ops.shape(beta))
644    alpha_broadcast = array_ops.broadcast_to(alpha, broadcast_shape)
645    seed1, seed2 = random_seed.get_seed(seed)
646    result = math_ops.maximum(
647        np.finfo(alpha.dtype.as_numpy_dtype).tiny,
648        gen_random_ops.random_gamma(
649            shape, alpha_broadcast, seed=seed1, seed2=seed2) / beta)
650    _maybe_set_static_shape_helper(result, shape, alpha_broadcast)
651    return result
652
653
654@tf_export(v1=["random.poisson", "random_poisson"])
655@dispatch.add_dispatch_support
656@deprecation.deprecated_endpoints("random_poisson")
657def random_poisson(lam, shape, dtype=dtypes.float32, seed=None, name=None):
658  """Draws `shape` samples from each of the given Poisson distribution(s).
659
660  `lam` is the rate parameter describing the distribution(s).
661
662  Example:
663
664  ```python
665  samples = tf.random.poisson([0.5, 1.5], [10])
666  # samples has shape [10, 2], where each slice [:, 0] and [:, 1] represents
667  # the samples drawn from each distribution
668
669  samples = tf.random.poisson([12.2, 3.3], [7, 5])
670  # samples has shape [7, 5, 2], where each slice [:, :, 0] and [:, :, 1]
671  # represents the 7x5 samples drawn from each of the two distributions
672  ```
673
674  Args:
675    lam: A Tensor or Python value or N-D array of type `dtype`.
676      `lam` provides the rate parameter(s) describing the poisson
677      distribution(s) to sample.
678    shape: A 1-D integer Tensor or Python array. The shape of the output samples
679      to be drawn per "rate"-parameterized distribution.
680    dtype: The type of the output: `float16`, `float32`, `float64`, `int32` or
681      `int64`.
682    seed: A Python integer. Used to create a random seed for the distributions.
683      See
684      `tf.random.set_seed`
685      for behavior.
686    name: Optional name for the operation.
687
688  Returns:
689    samples: a `Tensor` of shape `tf.concat([shape, tf.shape(lam)], axis=0)`
690      with values of type `dtype`.
691  """
692  return random_poisson_v2(shape, lam, dtype, seed, name)
693
694
695@tf_export("random.poisson", v1=[])
696@dispatch.add_dispatch_support
697def random_poisson_v2(shape, lam, dtype=dtypes.float32, seed=None, name=None):
698  """Draws `shape` samples from each of the given Poisson distribution(s).
699
700  `lam` is the rate parameter describing the distribution(s).
701
702  Example:
703
704  ```python
705  samples = tf.random.poisson([10], [0.5, 1.5])
706  # samples has shape [10, 2], where each slice [:, 0] and [:, 1] represents
707  # the samples drawn from each distribution
708
709  samples = tf.random.poisson([7, 5], [12.2, 3.3])
710  # samples has shape [7, 5, 2], where each slice [:, :, 0] and [:, :, 1]
711  # represents the 7x5 samples drawn from each of the two distributions
712  ```
713
714  Args:
715    shape: A 1-D integer Tensor or Python array. The shape of the output samples
716      to be drawn per "rate"-parameterized distribution.
717    lam: A Tensor or Python value or N-D array of type `dtype`.
718      `lam` provides the rate parameter(s) describing the poisson
719      distribution(s) to sample.
720    dtype: The type of the output: `float16`, `float32`, `float64`, `int32` or
721      `int64`.
722    seed: A Python integer. Used to create a random seed for the distributions.
723      See
724      `tf.random.set_seed`
725      for behavior.
726    name: Optional name for the operation.
727
728  Returns:
729    samples: a `Tensor` of shape `tf.concat([shape, tf.shape(lam)], axis=0)`
730      with values of type `dtype`.
731  """
732  with ops.name_scope(name, "random_poisson", [lam, shape]):
733    shape = ops.convert_to_tensor(shape, name="shape", dtype=dtypes.int32)
734    seed1, seed2 = random_seed.get_seed(seed)
735    result = gen_random_ops.random_poisson_v2(
736        shape, lam, dtype=dtype, seed=seed1, seed2=seed2)
737    _maybe_set_static_shape_helper(result, shape, lam)
738    return result
739