Itās kind of hard to answer just with writing, I think that a schematic will help explain whatās going on. In your example with the HalfNormal
, the transform will get in the way and make a separate FreeRV
called __log_{your_halfnormal_name}
, and the HalfNormal
itself will become a TransformedRV
. The dependency graph from theano will look something like this:
and in general it would look like this:
In your example with the sum_to_1
transform you can ask theano to print the weights
tensor computational graph like this:
>>> theano.printing.debugprint(weights)
ViewOp [id A] 'weights'
|Join [id B] ''
|TensorConstant{0} [id C]
|Subtensor{::} [id D] ''
| |weights_sumto1__ [id E]
|Elemwise{sub,no_inplace} [id F] ''
|InplaceDimShuffle{x} [id G] ''
| |TensorConstant{1} [id H]
|InplaceDimShuffle{x} [id I] ''
|Sum{axis=[0], acc_dtype=float64} [id J] ''
|Subtensor{::} [id K] ''
|weights_sumto1__ [id E]
So, as you can see, basically, pymc3 always puts an rv higher up the hierarchy. When you call sample
, the transformed (weights_sumto1__
) will be used as the FreeRV
, and the weights
value will be computed as a Deterministic
. So in the end, the sampled trace will have the samples of both weights_sumto1__
and weights
. In sample posterior predictive, nothing very special happens, the values for each of the nodes are grabbed straight out of the trace.
The complicated part happens in sample prior predictive. What goes on is that we first try to draw a value from weights_sumto1__
, that will raise a MissingInputError
because we didnāt provide the computational graphās input value. After that, we simply call the weights
random method and return its value as it came out, because we assume that the samples from weights
already lie in the proper sample space.
To get what you want (weights that are constrained to sum to one), you have to be a bit more explicit:
import pymc3 as pm
from theano import tensor as tt
with pm.Model() as histogram_model:
weights_raw = pm.HalfNormal('weights', shape=10)
weights = weights_raw / tt.sum(weights_raw, axis=-1, keepdims=True)
pm.Dirichlet('obs', a=weights, shape=10)
If youāre interested in storing the values of weights
when you sample
from your model (or draw prior predictive samples), you just have to wrap it with a Deterministic
.