ContinuousBernoulli
DistributionContinuousBernoulli(probs: Tensor | float | None = None, logits: Tensor | float | None = None, validate_args: bool | None = None)Continuous Bernoulli distribution on .
A continuous relaxation of the lucid.distributions.Bernoulli
distribution introduced by Loaiza-Ganem & Cunningham (2019) to fix the
well-known bias incurred by VAE decoders that use a Bernoulli
likelihood on real-valued image pixels in . Unlike the
naive "Bernoulli on [0,1]" likelihood, the Continuous Bernoulli has a
proper normalising constant and yields unbiased ELBO gradients.
Parameters
Notes
Probability density on :
where the normalising constant is
Mean (closed form):
Variance (closed form, ):
Both closed forms are differences of terms of order , which cancel catastrophically as ; within the mean and variance are evaluated from their Taylor series in instead.
Important properties:
- Support: (continuous, not just ).
- Reduces to at .
- At or the density concentrates near 0 or 1 respectively.
- Reparameterisable via inverse CDF.
The Continuous Bernoulli is the correct likelihood for decoders that output a value in (e.g. MNIST pixel intensities) when the model is to remain a valid probabilistic model. Using a plain Bernoulli on continuous data produces an improper density and a systematically biased ELBO.
Examples
>>> import lucid
>>> from lucid.distributions import ContinuousBernoulli
>>> d = ContinuousBernoulli(probs=0.7)
>>> d.rsample((4,)).shape
(4,)
>>> d.log_prob(lucid.tensor(0.5))
tensor(-0.02974)Used by 2
Constructors
1__init__
→None__init__(probs: Tensor | float | None = None, logits: Tensor | float | None = None, validate_args: bool | None = None)Properties
2Mean .
The second term is . Near the two terms cancel, so there the Taylor series in is used.
Examples
>>> import lucid
>>> from lucid.distributions import ContinuousBernoulli
>>> ContinuousBernoulli(probs=lucid.tensor([0.2, 0.5, 0.7])).mean
tensor([0.388, 0.5, 0.5698])Variance .
. The two terms are each of order and cancel near , so there the Taylor series in is used. Nothing is clamped: the variance is positive for every , and a negative value would be a defect to see, not to hide.
Examples
>>> import lucid
>>> from lucid.distributions import ContinuousBernoulli
>>> ContinuousBernoulli(probs=lucid.tensor([0.2, 0.5, 0.7])).variance
tensor([0.0759, 0.08333, 0.08043])Instance methods
7Cumulative distribution function of the Continuous Bernoulli.
with , and at . The second form has no cancellation as , where the reference framework replaces the first with inside ; there the two differ by up to , and this is the exact value.
Returns probabilities in ; 0 at and below 0, 1 at and above 1.
Examples
>>> import lucid
>>> from lucid.distributions import ContinuousBernoulli
>>> ContinuousBernoulli(probs=0.7).cdf(lucid.tensor(0.5))
tensor(0.3956)Shannon entropy of the Continuous Bernoulli (in nats).
with
,
so it reuses mean and the normaliser, each already evaluated
by its series near .
Returns
TensorEntropy in nats, shape batch_shape; 0 at
, where the distribution is uniform.
Examples
>>> import lucid
>>> from lucid.distributions import ContinuousBernoulli
>>> ContinuousBernoulli(probs=0.5).entropy()
tensor(0.)Quantile function of the Continuous Bernoulli.
for , reflected through for , and at .
Returns quantiles in .
Examples
>>> import lucid
>>> from lucid.distributions import ContinuousBernoulli
>>> ContinuousBernoulli(probs=0.7).icdf(lucid.tensor(0.3956))
tensor(0.5)x · l − softplus(l) + log C(p).
softplus rather than log(1 + exp(l)), which reached inf
at l ≈ 89 in float32; and the logit of a probs of exactly
0 or 1 is taken one epsilon inside [0, 1] (logits), so it
is never multiplied by a zero x while infinite.
Log-odds of — as given, or derived on access.
Derived from probs clamped one epsilon inside , as
the reference framework derives it.
Parameter — as given, or sigmoid(logits).
Reparameterised sample via the closed-form icdf.