if sample_shape_static_val is None: if ndims is None or not sample_shape.get_shape().is_fully_defined( ): ndims = array_ops.rank(sample_shape) expanded_shape = distribution_util.pick_vector( math_ops.equal(ndims, 0), np.array((1, ), dtype=dtypes.int32.as_numpy_dtype()), array_ops.shape(sample_shape)) sample_shape = array_ops.reshape(sample_shape, expanded_shape) total = math_ops.reduce_prod(sample_shape) # reduce_prod([]) == 1 else: if ndims is None: raise ValueError( "Shouldn't be here; ndims cannot be none when we have a " "tf.constant shape.") if ndims == 0: sample_shape_static_val = np.reshape(sample_shape_static_val, [1]) sample_shape = ops.convert_to_tensor(sample_shape_static_val, dtype=dtypes.int32, name="sample_shape") total = np.prod(sample_shape_static_val, dtype=dtypes.int32.as_numpy_dtype()) return sample_shape, total distribution_util.append_class_fun_doc(BaseDistribution.sample_n, doc_str=Distribution.sample_n.__doc__) distribution_util.append_class_fun_doc(BaseDistribution.log_prob, doc_str=Distribution.log_prob.__doc__)
ndims = sample_shape.get_shape().ndims if sample_shape_static_val is None: if ndims is None or not sample_shape.get_shape().is_fully_defined(): ndims = array_ops.rank(sample_shape) expanded_shape = distribution_util.pick_vector( math_ops.equal(ndims, 0), np.array((1,), dtype=dtypes.int32.as_numpy_dtype()), array_ops.shape(sample_shape)) sample_shape = array_ops.reshape(sample_shape, expanded_shape) total = math_ops.reduce_prod(sample_shape) # reduce_prod([]) == 1 else: if ndims is None: raise ValueError( "Shouldn't be here; ndims cannot be none when we have a " "tf.constant shape.") if ndims == 0: sample_shape_static_val = np.reshape(sample_shape_static_val, [1]) sample_shape = ops.convert_to_tensor( sample_shape_static_val, dtype=dtypes.int32, name="sample_shape") total = np.prod(sample_shape_static_val, dtype=dtypes.int32.as_numpy_dtype()) return sample_shape, total distribution_util.append_class_fun_doc(BaseDistribution.sample_n, doc_str=Distribution.sample_n.__doc__) distribution_util.append_class_fun_doc(BaseDistribution.log_prob, doc_str=Distribution.log_prob.__doc__)
message="mode not defined for components of alpha <= 1") ], mode) def _assert_valid_sample(self, x): if not self.validate_args: return x return control_flow_ops.with_dependencies([ check_ops.assert_positive(x), distribution_util.assert_close( array_ops.ones((), dtype=self.dtype), math_ops.reduce_sum(x, reduction_indices=[-1])), ], x) _prob_note = """ Note that the input must be a non-negative tensor with dtype `dtype` and whose shape can be broadcast with `self.alpha`. For fixed leading dimensions, the last dimension represents counts for the corresponding Dirichlet distribution in `self.alpha`. `x` is only legal if it sums up to one. """ distribution_util.append_class_fun_doc(Dirichlet.log_prob, doc_str=_prob_note) distribution_util.append_class_fun_doc(Dirichlet.prob, doc_str=_prob_note) distribution_util.append_class_fun_doc(Dirichlet.mode, doc_str=""" Note that the mode for the Dirichlet distribution is only defined when `alpha > 1`. This returns the mode when `alpha > 1`, and NaN otherwise. If `self.allow_nan_stats` is `False`, an exception will be raised rather than returning `NaN`. """)
return control_flow_ops.with_dependencies([ check_ops.assert_non_negative( counts, message="counts has negative components."), check_ops.assert_less_equal( counts, self._n, message="counts are not less than or equal to n."), distribution_util.assert_integer_form( counts, message="counts have non-integer components.")], counts) _prob_note = """ For each batch member of counts `k`, `P[counts]` is the probability that after sampling `n` draws from this Binomial distribution, the number of successes is `k`. Note that different sequences of draws can result in the same counts, thus the probability includes a combinatorial coefficient. counts: Non-negative tensor with dtype `dtype` and whose shape can be broadcast with `self.p` and `self.n`. `counts` is only legal if it is less than or equal to `n` and its components are equal to integer values. """ distribution_util.append_class_fun_doc(Binomial.log_prob, doc_str=_prob_note) distribution_util.append_class_fun_doc(Binomial.prob, doc_str=_prob_note) distribution_util.append_class_fun_doc(Binomial.mode, doc_str=""" Note that when `(n + 1) * p` is an integer, there are actually two modes. Namely, `(n + 1) * p` and `(n + 1) * p - 1` are both modes. Here we return only the larger of the two modes. """)
accurate for large values of `y`, and in this case the `survival_function` must also be defined on `y - 1`. """ ) _log_prob_note = ( _prob_base_note + """ The base distribution's `log_cdf` method must be defined on `y - 1`. If the base distribution has a `log_survival_function` method results will be more accurate for large values of `y`, and in this case the `log_survival_function` must also be defined on `y - 1`. """ ) distribution_util.append_class_fun_doc(QuantizedDistribution.prob, doc_str=_prob_note) distribution_util.append_class_fun_doc(QuantizedDistribution.log_prob, doc_str=_log_prob_note) _cdf_base_note = """ For whole numbers `y`, ``` cdf(y) := P[Y <= y] = 1, if y >= upper_cutoff, = 0, if y < lower_cutoff, = P[X <= y], otherwise. ``` Since `Y` only has mass at whole numbers, `P[Y <= y] = P[Y <= floor(y)]`.
nan = np.array(np.nan, dtype=self.dtype.as_numpy_dtype()) return math_ops.select( self.alpha >= 1., mode, array_ops.fill(self.batch_shape(), nan, name="nan")) else: return control_flow_ops.with_dependencies([ check_ops.assert_less( array_ops.ones((), self.dtype), self.alpha, message="mode not defined for components of alpha <= 1"), ], mode) distribution_util.append_class_fun_doc(Gamma.sample_n, doc_str=""" See the documentation for tf.random_gamma for more details. """) distribution_util.append_class_fun_doc(Gamma.entropy, doc_str=""" This is defined to be ``` entropy = alpha - log(beta) + log(Gamma(alpha)) + (1-alpha)digamma(alpha) ``` where digamma(alpha) is the digamma function. """) distribution_util.append_class_fun_doc(Gamma.mode, doc_str="""
check_ops.assert_positive( x, message="Negative events lie outside Beta distribution support." ), check_ops.assert_less( x, array_ops.ones((), self.dtype), message="Event>=1 lies outside Beta distribution support."), ], x) _prob_note = """ Note that the argument `x` must be a non-negative floating point tensor whose shape can be broadcast with `self.a` and `self.b`. For fixed leading dimensions, the last dimension represents counts for the corresponding Beta distribution in `self.a` and `self.b`. `x` is only legal if `0 < x < 1`. """ distribution_util.append_class_fun_doc(Beta.log_prob, doc_str=_prob_note) distribution_util.append_class_fun_doc(Beta.prob, doc_str=_prob_note) distribution_util.append_class_fun_doc(Beta.mode, doc_str=""" Note that the mode for the Beta distribution is only defined when `a > 1`, `b > 1`. This returns the mode when `a > 1` and `b > 1`, and `NaN` otherwise. If `self.allow_nan_stats` is `False`, an exception will be raised rather than returning `NaN`. """)
def _mean(self): return array_ops.identity(self.p) def _variance(self): return self.q * self.p def _std(self): return math_ops.sqrt(self._variance()) def _mode(self): return math_ops.cast(self.p > self.q, self.dtype) distribution_util.append_class_fun_doc(Bernoulli.mode, doc_str=""" Specific notes: 1 if p > 1-p. 0 otherwise. """) @kullback_leibler.RegisterKL(Bernoulli, Bernoulli) def _kl_bernoulli_bernoulli(a, b, name=None): """Calculate the batched KL divergence KL(a || b) with a and b Bernoulli. Args: a: instance of a Bernoulli distribution object. b: instance of a Bernoulli distribution object. name: (optional) Name to use for created operations. default is "kl_bernoulli_bernoulli". Returns:
counts, self._n, message="counts are not less than or equal to n."), distribution_util.assert_integer_form( counts, message="counts have non-integer components.") ], counts) _prob_note = """ For each batch member of counts `k`, `P[counts]` is the probability that after sampling `n` draws from this Binomial distribution, the number of successes is `k`. Note that different sequences of draws can result in the same counts, thus the probability includes a combinatorial coefficient. counts: Non-negative tensor with dtype `dtype` and whose shape can be broadcast with `self.p` and `self.n`. `counts` is only legal if it is less than or equal to `n` and its components are equal to integer values. """ distribution_util.append_class_fun_doc(Binomial.log_prob, doc_str=_prob_note) distribution_util.append_class_fun_doc(Binomial.prob, doc_str=_prob_note) distribution_util.append_class_fun_doc(Binomial.mode, doc_str=""" Note that when `(n + 1) * p` is an integer, there are actually two modes. Namely, `(n + 1) * p` and `(n + 1) * p - 1` are both modes. Here we return only the larger of the two modes. """)
message="variance not defined for components of df <= 1"), ], result_where_defined) def _std(self): return math_ops.sqrt(self.variance()) def _mode(self): return array_ops.identity(self.mu) def _ones(self): return array_ops.ones(self.batch_shape(), dtype=self.dtype) distribution_util.append_class_fun_doc(StudentT.mean, doc_str=""" The mean of Student's T equals `mu` if `df > 1`, otherwise it is `NaN`. If `self.allow_nan_stats=False`, then an exception will be raised rather than returning `NaN`. """) distribution_util.append_class_fun_doc(StudentT.variance, doc_str=""" Variance for Student's T equals ``` df / (df - 2), when df > 2 infinity, when 1 < df <= 2 NaN, when df <= 1 ``` """)
return math_ops.sqrt(self.variance()) def _mode(self): return math_ops.floor(self.lam) def _assert_valid_sample(self, x, check_integer=True): if not self.validate_args: return x with ops.name_scope('check_x', values=[x]): dependencies = [check_ops.assert_non_negative(x)] if check_integer: dependencies += [distribution_util.assert_integer_form( x, message="x has non-integer components.")] return control_flow_ops.with_dependencies(dependencies, x) _prob_note = """ Note thet the input value must be a non-negative floating point tensor with dtype `dtype` and whose shape can be broadcast with `self.lam`. `x` is only legal if it is non-negative and its components are equal to integer values. """ distribution_util.append_class_fun_doc(Poisson.log_prob, doc_str=_prob_note) distribution_util.append_class_fun_doc(Poisson.prob, doc_str=_prob_note) distribution_util.append_class_fun_doc(Poisson.mode, doc_str=""" Note that when `lam` is an integer, there are actually two modes. Namely, `lam` and `lam - 1` are both modes. Here we return only the larger of the two modes. """)
_prob_note = """ For each batch of counts `[n_1,...,n_k]`, `P[counts]` is the probability that after sampling `n` draws from this Dirichlet Multinomial distribution, the number of draws falling in class `j` is `n_j`. Note that different sequences of draws can result in the same counts, thus the probability includes a combinatorial coefficient. Note that input, "counts", must be a non-negative tensor with dtype `dtype` and whose shape can be broadcast with `self.alpha`. For fixed leading dimensions, the last dimension represents counts for the corresponding Dirichlet Multinomial distribution in `self.alpha`. `counts` is only legal if it sums up to `n` and its components are equal to integer values. """ distribution_util.append_class_fun_doc(DirichletMultinomial.log_prob, doc_str=_prob_note) distribution_util.append_class_fun_doc(DirichletMultinomial.prob, doc_str=_prob_note) distribution_util.append_class_fun_doc(DirichletMultinomial.variance, doc_str=""" The variance for each batch member is defined as the following: ``` Var(X_j) = n * alpha_j / alpha_0 * (1 - alpha_j / alpha_0) * (n + alpha_0) / (1 + alpha_0) ``` where `alpha_0 = sum_j alpha_j`.
], result_where_defined) def _std(self): return math_ops.sqrt(self.variance()) def _mode(self): return array_ops.identity(self.mu) def _ones(self): return array_ops.ones(self.batch_shape(), dtype=self.dtype) distribution_util.append_class_fun_doc(StudentT.mean, doc_str=""" The mean of Student's T equals `mu` if `df > 1`, otherwise it is `NaN`. If `self.allow_nan_stats=False`, then an exception will be raised rather than returning `NaN`. """) distribution_util.append_class_fun_doc(StudentT.variance, doc_str=""" Variance for Student's T equals ``` df / (df - 2), when df > 2 infinity, when 1 < df <= 2 NaN, when df <= 1 ```
check_ops.assert_positive(x, message="Negative events lie outside Beta distribution support."), check_ops.assert_less( x, array_ops.ones((), self.dtype), message="Event>=1 lies outside Beta distribution support." ), ], x, ) _prob_note = """ Note that the argument `x` must be a non-negative floating point tensor whose shape can be broadcast with `self.a` and `self.b`. For fixed leading dimensions, the last dimension represents counts for the corresponding Beta distribution in `self.a` and `self.b`. `x` is only legal if `0 < x < 1`. """ distribution_util.append_class_fun_doc(Beta.log_prob, doc_str=_prob_note) distribution_util.append_class_fun_doc(Beta.prob, doc_str=_prob_note) distribution_util.append_class_fun_doc( Beta.mode, doc_str=""" Note that the mode for the Beta distribution is only defined when `a > 1`, `b > 1`. This returns the mode when `a > 1` and `b > 1`, and `NaN` otherwise. If `self.allow_nan_stats` is `False`, an exception will be raised rather than returning `NaN`. """, )
y = ops.convert_to_tensor(y, name="y") with ops.name_scope("inverse"): if y in self._inverse_cache: x = self._inverse_cache[y] elif self.inverse: x = self.inverse(y) else: raise ValueError("No inverse function exists and input `y` was not " "returned from `sample`.") return x distribution_util.append_class_fun_doc( TransformedDistribution.batch_shape, doc_str=""" The product of the dimensions of the `batch_shape` is the number of independent distributions of this kind the instance represents. """, ) distribution_util.append_class_fun_doc( TransformedDistribution.sample_n, doc_str=""" Samples from the base distribution and then passes through the transform. """, ) distribution_util.append_class_fun_doc( TransformedDistribution.log_prob,
return math_ops.floor(self.lam) def _assert_valid_sample(self, x, check_integer=True): if not self.validate_args: return x with ops.name_scope("check_x", values=[x]): dependencies = [check_ops.assert_non_negative(x)] if check_integer: dependencies += [ distribution_util.assert_integer_form( x, message="x has non-integer components.") ] return control_flow_ops.with_dependencies(dependencies, x) _prob_note = """ Note thet the input value must be a non-negative floating point tensor with dtype `dtype` and whose shape can be broadcast with `self.lam`. `x` is only legal if it is non-negative and its components are equal to integer values. """ distribution_util.append_class_fun_doc(Poisson.log_prob, doc_str=_prob_note) distribution_util.append_class_fun_doc(Poisson.prob, doc_str=_prob_note) distribution_util.append_class_fun_doc(Poisson.mode, doc_str=""" Note that when `lam` is an integer, there are actually two modes. Namely, `lam` and `lam - 1` are both modes. Here we return only the larger of the two modes. """)
def _mode(self): return array_ops.identity(self._mu) _prob_note = """ `x` is a batch vector with compatible shape if `x` is a `Tensor` whose shape can be broadcast up to either: ```` self.batch_shape + self.event_shape OR [M1,...,Mm] + self.batch_shape + self.event_shape ``` """ distribution_util.append_class_fun_doc(_MultivariateNormalOperatorPD.log_prob, doc_str=_prob_note) distribution_util.append_class_fun_doc(_MultivariateNormalOperatorPD.prob, doc_str=_prob_note) class MultivariateNormalDiag(_MultivariateNormalOperatorPD): """The multivariate normal distribution on `R^k`. This distribution is defined by a 1-D mean `mu` and a 1-D diagonal `diag_stdev`, representing the standard deviations. This distribution assumes the random variables, `(X_1,...,X_k)` are independent, thus no non-diagonal terms of the covariance matrix are needed. This allows for `O(k)` pdf evaluation, sampling, and storage. #### Mathematical details
def _mean(self): return array_ops.identity(self.p) def _variance(self): return self.q * self.p def _std(self): return math_ops.sqrt(self._variance()) def _mode(self): return math_ops.cast(self.p > self.q, self.dtype) distribution_util.append_class_fun_doc(Bernoulli.mode, doc_str=""" Specific notes: 1 if p > 1-p. 0 otherwise. """) class BernoulliWithSigmoidP(Bernoulli): """Bernoulli with `p = sigmoid(p)`.""" def __init__(self, p=None, dtype=dtypes.int32, validate_args=False, allow_nan_stats=True, name="BernoulliWithSigmoidP"): with ops.name_scope(name) as ns: super(BernoulliWithSigmoidP, self).__init__(
def _assert_valid_sample(self, counts): """Check counts for proper shape, values, then return tensor version.""" if not self.validate_args: return counts return control_flow_ops.with_dependencies([ check_ops.assert_non_negative( counts, message="counts has negative components."), check_ops.assert_equal( self.n, math_ops.reduce_sum(counts, reduction_indices=[-1]), message="counts do not sum to n."), distribution_util.assert_integer_form( counts, message="counts have non-integer components.") ], counts) _prob_note = """ For each batch of counts `[n_1,...,n_k]`, `P[counts]` is the probability that after sampling `n` draws from this Multinomial distribution, the number of draws falling in class `j` is `n_j`. Note that different sequences of draws can result in the same counts, thus the probability includes a combinatorial coefficient. Note that input "counts" must be a non-negative tensor with dtype `dtype` and whose shape can be broadcast with `self.p` and `self.n`. For fixed leading dimensions, the last dimension represents counts for the corresponding Multinomial distribution in `self.p`. `counts` is only legal if it sums up to `n` and its components are equal to integer values. """ distribution_util.append_class_fun_doc(Multinomial.log_prob, doc_str=_prob_note) distribution_util.append_class_fun_doc(Multinomial.prob, doc_str=_prob_note)
else: raise ValueError( "No inverse function exists and input `y` was not " "returned from `sample`.") with ops.name_scope("log_det_jacobian"): log_det_jacobian = self.log_det_jacobian(x) return self.base_distribution.log_prob(x) - log_det_jacobian def _prob(self, y): return math_ops.exp(self._log_prob(y)) distribution_util.append_class_fun_doc(TransformedDistribution.batch_shape, doc_str=""" The product of the dimensions of the `batch_shape` is the number of independent distributions of this kind the instance represents. """) distribution_util.append_class_fun_doc(TransformedDistribution.sample_n, doc_str=""" Samples from the base distribution and then passes through the transform. """) distribution_util.append_class_fun_doc(TransformedDistribution.log_prob, doc_str=""" `(log o p o g)(y) - (log o det o J o g)(y)`, where `g` is the inverse of `transform`.
nan = np.array(np.nan, dtype=self.dtype.as_numpy_dtype()) return math_ops.select( self.alpha >= 1., mode, array_ops.fill(self.batch_shape(), nan, name="nan")) else: return control_flow_ops.with_dependencies([ check_ops.assert_less( array_ops.ones((), self.dtype), self.alpha, message="mode not defined for components of alpha <= 1"), ], mode) distribution_util.append_class_fun_doc(Gamma.sample_n, doc_str=""" See the documentation for tf.random_gamma for more details. """) distribution_util.append_class_fun_doc(Gamma.entropy, doc_str=""" This is defined to be ``` entropy = alpha - log(beta) + log(Gamma(alpha)) + (1-alpha)digamma(alpha) ``` where digamma(alpha) is the digamma function. """)
_prob_note = _prob_base_note + """ The base distribution's `cdf` method must be defined on `y - 1`. If the base distribution has a `survival_function` method, results will be more accurate for large values of `y`, and in this case the `survival_function` must also be defined on `y - 1`. """ _log_prob_note = _prob_base_note + """ The base distribution's `log_cdf` method must be defined on `y - 1`. If the base distribution has a `log_survival_function` method results will be more accurate for large values of `y`, and in this case the `log_survival_function` must also be defined on `y - 1`. """ distribution_util.append_class_fun_doc(QuantizedDistribution.prob, doc_str=_prob_note) distribution_util.append_class_fun_doc(QuantizedDistribution.log_prob, doc_str=_log_prob_note) _cdf_base_note = """ For whole numbers `y`, ``` cdf(y) := P[Y <= y] = 1, if y >= upper_cutoff, = 0, if y < lower_cutoff, = P[X <= y], otherwise. ```