Transforms#
Introduction#
Random variables in an Aesara model graph can be transformed by AePPL in multiple ways.
One way is by explicitly constructing a transform using Aesara Op
s within a model graph:
A_rv = at.random.normal(0, 1.0, name="A")
Z_rv = at.exp(A_rv)
Z_rv.name = "Z"
logp, (z_vv,) = joint_logprob(Z_rv)
The resulting log-density should reflect the “change-of-variables” implied by taking the exponential of a normal random variable:
>>> print(aesara.pprint(logp))
((-0.9189385332046727 + (-0.5 * (log(Z_vv) ** 2))) + (-1.0 * log(Z_vv)))
Transforms can also be applied implicitly through the use of TransformValuesRewrite
:
A_rv = at.random.normal(0, 1.0, name="A")
B_rv = at.random.normal(A_rv, 1.0, name="B")
logp, (a_vv, b_vv,) = joint_logprob(
A_rv,
B_rv,
extra_rewrites=TransformValuesRewrite(
{A_rv: ExpTransform()}
),
)
This approach will apply the designated transforms to all occurrences of their associated variables and their values:
>>> print(aesara.pprint(logp))
sum([((-0.9189385332046727 + (-0.5 * (log(A_vv-trans) ** 2))) + (-1.0 * log(A_vv-trans))),
(-0.9189385332046727 + (-0.5 * ((B_vv - log(A_vv-trans)) ** 2)))], axis=None)
TransformValuesRewrite
#
- class aeppl.transforms.TransformValuesRewrite(rvs_to_transforms)[source]#
Transforms measurable variables.
This transformation can be used to replace all occurrences of a measurable variable and its values within a model graph with a transformed version of itself (e.g. for the purposes of sampling on “unconstrained” ranges).
Example
A_rv = at.random.normal(0, 1.0, name="A") B_rv = at.random.normal(A_rv, 1.0, name="B") logp, (a_vv, b_vv) = joint_logprob( A_rv, B_rv, extra_rewrites=TransformValuesRewrite( {A_rv: ExpTransform()} ), ) >>> print(aesara.pprint(logp)) sum([((-0.9189385332046727 + (-0.5 * (log(A_vv-trans) ** 2))) + (-1.0 * log(A_vv-trans))), (-0.9189385332046727 + (-0.5 * ((B_vv - log(A_vv-trans)) ** 2)))], axis=None)
Invertible transforms#
AePPL currently supports transforms using the following (invertible) Aesara operators. This means that AePPL can compute the log-probability of a random variable that is the result of one of the following transformations applied to another random variable:
aesara.tensor.add
aesara.tensor.sub
aesara.tensor.mul
aesara.tensor.true_divide
aesara.tensor.exponential
aesara.tensor.exp
aesara.tensor.log
One can also apply the following transforms directly:
These transformations can be chained using:
Censoring#
AePPL can compute the log-density of aesara.tensor.clip
applied to a random variable:
- aeppl.censoring.clip_logprob(op, values, base_rv, lower_bound, upper_bound, **kwargs)[source]#
Logprob of a clipped censored distribution
The probability is given by
\[\begin{split}\begin{cases} 0 & \text{for } x < lower, \\ \text{CDF}(lower, dist) & \text{for } x = lower, \\ \text{P}(x, dist) & \text{for } lower < x < upper, \\ 1-\text{CDF}(upper, dist) & \text {for} x = upper, \\ 0 & \text{for } x > upper, \end{cases}\end{split}\]
Rounding#
AePPL can compute the log-density of aesara.tensor.ceil
, aesara.tensor.floor
, or aesara.tensor.round_half_to_even
applied to a random variable:
- aeppl.censoring.round_logprob(op, values, base_rv, **kwargs)[source]#
Logprob of a rounded censored distribution
The probability of a distribution rounded to the nearest integer is given by
\[\begin{split}\begin{cases} \text{CDF}(x+\frac{1}{2}, dist) - \text{CDF}(x-\frac{1}{2}, dist) & \text{for } x \in \mathbb{Z}, \\ 0 & \text{otherwise}, \end{cases}\end{split}\]The probability of a distribution rounded up is given by
\[\begin{split}\begin{cases} \text{CDF}(x, dist) - \text{CDF}(x-1, dist) & \text{for } x \in \mathbb{Z}, \\ 0 & \text{otherwise}, \end{cases}\end{split}\]The probability of a distribution rounded down is given by
\[\begin{split}\begin{cases} \text{CDF}(x+1, dist) - \text{CDF}(x, dist) & \text{for } x \in \mathbb{Z}, \\ 0 & \text{otherwise}, \end{cases}\end{split}\]