| # Copyright 2018 The TensorFlow Authors. All Rights Reserved. |
| # |
| # Licensed 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. |
| # ============================================================================== |
| """Stateless random ops which take seed as a tensor input.""" |
| |
| from __future__ import absolute_import |
| from __future__ import division |
| from __future__ import print_function |
| |
| from tensorflow.python.framework import dtypes |
| from tensorflow.python.framework import ops |
| from tensorflow.python.framework import tensor_util |
| from tensorflow.python.ops import gen_stateless_random_ops |
| from tensorflow.python.ops import math_ops |
| from tensorflow.python.util import deprecation |
| from tensorflow.python.util.tf_export import tf_export |
| |
| ops.NotDifferentiable("StatelessMultinomial") |
| ops.NotDifferentiable("StatelessRandomNormal") |
| ops.NotDifferentiable("StatelessRandomUniform") |
| ops.NotDifferentiable("StatelessRandomUniformInt") |
| ops.NotDifferentiable("StatelessTruncatedNormal") |
| |
| |
| @tf_export("random.stateless_uniform") |
| def stateless_random_uniform(shape, |
| seed, |
| minval=0, |
| maxval=None, |
| dtype=dtypes.float32, |
| name=None): |
| """Outputs deterministic pseudorandom values from a uniform distribution. |
| |
| This is a stateless version of `tf.random.uniform`: if run twice with the |
| same seeds, it will produce the same pseudorandom numbers. The output is |
| consistent across multiple runs on the same hardware (and between CPU |
| and GPU), but may change between versions of TensorFlow or on non-CPU/GPU |
| hardware. |
| |
| The generated values follow a uniform distribution in the range |
| `[minval, maxval)`. The lower bound `minval` is included in the range, while |
| the upper bound `maxval` is excluded. |
| |
| For floats, the default range is `[0, 1)`. For ints, at least `maxval` must |
| be specified explicitly. |
| |
| In the integer case, the random integers are slightly biased unless |
| `maxval - minval` is an exact power of two. The bias is small for values of |
| `maxval - minval` significantly smaller than the range of the output (either |
| `2**32` or `2**64`). |
| |
| Args: |
| shape: A 1-D integer Tensor or Python array. The shape of the output tensor. |
| seed: A shape [2] integer Tensor of seeds to the random number generator. |
| minval: A 0-D Tensor or Python value of type `dtype`. The lower bound on the |
| range of random values to generate. Defaults to 0. |
| maxval: A 0-D Tensor or Python value of type `dtype`. The upper bound on the |
| range of random values to generate. Defaults to 1 if `dtype` is floating |
| point. |
| dtype: The type of the output: `float16`, `float32`, `float64`, `int32`, or |
| `int64`. |
| name: A name for the operation (optional). |
| |
| Returns: |
| A tensor of the specified shape filled with random uniform values. |
| |
| Raises: |
| ValueError: If `dtype` is integral and `maxval` is not specified. |
| """ |
| dtype = dtypes.as_dtype(dtype) |
| if dtype not in (dtypes.float16, dtypes.bfloat16, dtypes.float32, |
| dtypes.float64, dtypes.int32, dtypes.int64): |
| raise ValueError("Invalid dtype %r" % dtype) |
| if maxval is None: |
| if dtype.is_integer: |
| raise ValueError("Must specify maxval for integer dtype %r" % dtype) |
| maxval = 1 |
| with ops.name_scope(name, "stateless_random_uniform", |
| [shape, seed, minval, maxval]) as name: |
| shape = tensor_util.shape_tensor(shape) |
| minval = ops.convert_to_tensor(minval, dtype=dtype, name="min") |
| maxval = ops.convert_to_tensor(maxval, dtype=dtype, name="max") |
| if dtype.is_integer: |
| result = gen_stateless_random_ops.stateless_random_uniform_int( |
| shape, seed=seed, minval=minval, maxval=maxval, name=name) |
| else: |
| rnd = gen_stateless_random_ops.stateless_random_uniform( |
| shape, seed=seed, dtype=dtype) |
| result = math_ops.add(rnd * (maxval - minval), minval, name=name) |
| tensor_util.maybe_set_static_shape(result, shape) |
| return result |
| |
| |
| @tf_export("random.stateless_normal") |
| def stateless_random_normal(shape, |
| seed, |
| mean=0.0, |
| stddev=1.0, |
| dtype=dtypes.float32, |
| name=None): |
| """Outputs deterministic pseudorandom values from a normal distribution. |
| |
| This is a stateless version of `tf.random.normal`: if run twice with the |
| same seeds, it will produce the same pseudorandom numbers. The output is |
| consistent across multiple runs on the same hardware (and between CPU |
| and GPU), but may change between versions of TensorFlow or on non-CPU/GPU |
| hardware. |
| |
| Args: |
| shape: A 1-D integer Tensor or Python array. The shape of the output tensor. |
| seed: A shape [2] integer Tensor of seeds to the random number generator. |
| mean: A 0-D Tensor or Python value of type `dtype`. The mean of the normal |
| distribution. |
| stddev: A 0-D Tensor or Python value of type `dtype`. The standard deviation |
| of the normal distribution. |
| dtype: The type of the output. |
| name: A name for the operation (optional). |
| |
| Returns: |
| A tensor of the specified shape filled with random normal values. |
| """ |
| with ops.name_scope(name, "stateless_random_normal", |
| [shape, seed, mean, stddev]) as name: |
| shape = tensor_util.shape_tensor(shape) |
| mean = ops.convert_to_tensor(mean, dtype=dtype, name="mean") |
| stddev = ops.convert_to_tensor(stddev, dtype=dtype, name="stddev") |
| rnd = gen_stateless_random_ops.stateless_random_normal(shape, seed, dtype) |
| result = math_ops.add(rnd * stddev, mean, name=name) |
| tensor_util.maybe_set_static_shape(result, shape) |
| return result |
| |
| |
| @tf_export("random.stateless_truncated_normal") |
| def stateless_truncated_normal(shape, |
| seed, |
| mean=0.0, |
| stddev=1.0, |
| dtype=dtypes.float32, |
| name=None): |
| """Outputs deterministic pseudorandom values, truncated normally distributed. |
| |
| This is a stateless version of `tf.random.truncated_normal`: if run twice with |
| the |
| same seeds, it will produce the same pseudorandom numbers. The output is |
| consistent across multiple runs on the same hardware (and between CPU |
| and GPU), but may change between versions of TensorFlow or on non-CPU/GPU |
| hardware. |
| |
| The generated values follow a normal distribution with specified mean and |
| standard deviation, except that values whose magnitude is more than 2 standard |
| deviations from the mean are dropped and re-picked. |
| |
| Args: |
| shape: A 1-D integer Tensor or Python array. The shape of the output tensor. |
| seed: A shape [2] integer Tensor of seeds to the random number generator. |
| mean: A 0-D Tensor or Python value of type `dtype`. The mean of the |
| truncated normal distribution. |
| stddev: A 0-D Tensor or Python value of type `dtype`. The standard deviation |
| of the normal distribution, before truncation. |
| dtype: The type of the output. |
| name: A name for the operation (optional). |
| |
| Returns: |
| A tensor of the specified shape filled with random truncated normal values. |
| """ |
| with ops.name_scope(name, "stateless_truncated_normal", |
| [shape, seed, mean, stddev]) as name: |
| shape = tensor_util.shape_tensor(shape) |
| mean = ops.convert_to_tensor(mean, dtype=dtype, name="mean") |
| stddev = ops.convert_to_tensor(stddev, dtype=dtype, name="stddev") |
| rnd = gen_stateless_random_ops.stateless_truncated_normal( |
| shape, seed, dtype) |
| result = math_ops.add(rnd * stddev, mean, name=name) |
| tensor_util.maybe_set_static_shape(result, shape) |
| return result |
| |
| |
| @tf_export(v1=["random.stateless_multinomial"]) |
| @deprecation.deprecated( |
| date=None, instructions="Use `tf.random.stateless_categorical` instead.") |
| def stateless_multinomial(logits, |
| num_samples, |
| seed, |
| output_dtype=dtypes.int64, |
| name=None): |
| """Draws deterministic pseudorandom samples from a multinomial distribution. |
| |
| This is a stateless version of `tf.random.categorical`: if run twice with the |
| same seeds, it will produce the same pseudorandom numbers. The output is |
| consistent across multiple runs on the same hardware (and between CPU |
| and GPU), but may change between versions of TensorFlow or on non-CPU/GPU |
| hardware. |
| |
| Example: |
| |
| ```python |
| # samples has shape [1, 5], where each value is either 0 or 1 with equal |
| # probability. |
| samples = tf.random.stateless_categorical( |
| tf.math.log([[0.5, 0.5]]), 5, seed=[7, 17]) |
| ``` |
| |
| Args: |
| logits: 2-D Tensor with shape `[batch_size, num_classes]`. Each slice |
| `[i, :]` represents the unnormalized log-probabilities for all classes. |
| num_samples: 0-D. Number of independent samples to draw for each row slice. |
| seed: A shape [2] integer Tensor of seeds to the random number generator. |
| output_dtype: integer type to use for the output. Defaults to int64. |
| name: Optional name for the operation. |
| |
| Returns: |
| The drawn samples of shape `[batch_size, num_samples]`. |
| """ |
| with ops.name_scope(name, "stateless_multinomial", [logits, seed]): |
| return stateless_multinomial_categorical_impl(logits, num_samples, |
| output_dtype, seed) |
| |
| |
| @tf_export("random.stateless_categorical") |
| def stateless_categorical(logits, |
| num_samples, |
| seed, |
| dtype=dtypes.int64, |
| name=None): |
| """Draws deterministic pseudorandom samples from a categorical distribution. |
| |
| This is a stateless version of `tf.categorical`: if run twice with the |
| same seeds, it will produce the same pseudorandom numbers. The output is |
| consistent across multiple runs on the same hardware (and between CPU |
| and GPU), but may change between versions of TensorFlow or on non-CPU/GPU |
| hardware. |
| |
| Example: |
| |
| ```python |
| # samples has shape [1, 5], where each value is either 0 or 1 with equal |
| # probability. |
| samples = tf.random.stateless_categorical( |
| tf.math.log([[0.5, 0.5]]), 5, seed=[7, 17]) |
| ``` |
| |
| Args: |
| logits: 2-D Tensor with shape `[batch_size, num_classes]`. Each slice |
| `[i, :]` represents the unnormalized log-probabilities for all classes. |
| num_samples: 0-D. Number of independent samples to draw for each row slice. |
| seed: A shape [2] integer Tensor of seeds to the random number generator. |
| dtype: integer type to use for the output. Defaults to int64. |
| name: Optional name for the operation. |
| |
| Returns: |
| The drawn samples of shape `[batch_size, num_samples]`. |
| """ |
| with ops.name_scope(name, "stateless_categorical", [logits, seed]): |
| return stateless_multinomial_categorical_impl(logits, num_samples, dtype, |
| seed) |
| |
| |
| def stateless_multinomial_categorical_impl(logits, num_samples, dtype, seed): |
| """Implementation for stateless multinomial/categorical ops (v1/v2).""" |
| logits = ops.convert_to_tensor(logits, name="logits") |
| return gen_stateless_random_ops.stateless_multinomial( |
| logits, num_samples, seed, output_dtype=dtype) |