Hi – I’m working on a complex model that requires enumeration combined with a likelihood defined by conditionally independent outcomes, given some parameters.
I’ve been able to distill the issue by taking the Toy Mixture Model example and adapting it to my situation as best I can
import jax
from jax import numpy as jnp
import numpyro
from numpyro import distributions as dist
from numpyro.ops.indexing import Vindex
Start by defining some fixed parameters
N=5
all_p_B = jnp.stack((
jnp.arange(1, N+1) / (2*N),
jnp.arange(N + 1,2*N + 1)/(2*N)
))
>>> print(all_p_B)
[[0.1 0.2 0.3 0.4 0.5 ]
[0.6 0.7 0.8 0.90000004 1. ]]
The models is then
def model():
# draw a decision
A = numpyro.sample(
"A",
dist.Bernoulli(0.5),
infer={"enumerate": "parallel"}
)
print(f"A.shape={A.shape}")
# choose (using Vindex for correctness) the corresponding set of params
chosen_p_B = Vindex(all_p_B)[A]
numpyro.deterministic('chosen_p_B', chosen_p_B)
print(f"chosen_p_B.shape={chosen_p_B.shape}")
# evaluate likelihood given the selected params for each observation
with numpyro.plate("data_plate", N):
B = numpyro.sample(
"B",
dist.Bernoulli(chosen_p_B),
obs = jnp.ones(N, dtype=A.dtype)
)
Now, sampling from the prior works
rng_key = jax.random.key(5)
rng_key, seed_key = jax.random.split(rng_key)
seeded_model = numpyro.handlers.seed(model, seed_key)
exec_trace = numpyro.handlers.trace(seeded_model).get_trace()
A.shape=()
chosen_p_B.shape=(5,)
>>> for k,v in exec_trace.items():
... if v['type'] != 'plate':
... print(f"{k}: {v['value']}")
...
A: 1
chosen_p_B: [0.6 0.7 0.8 0.90000004 1. ]
B: [1 1 1 1 1]
But initialization fails
rng_key, init_key = jax.random.split(rng_key)
(
params_info,
potential_fn_gen,
postprocess_fn,
model_trace,
) = numpyro.infer.util.initialize_model(
init_key,
model,
dynamic_args=True,
init_strategy=numpyro.infer.init_to_sample, # initialize from the prior
)
A.shape=()
chosen_p_B.shape=(5,)
A.shape=()
chosen_p_B.shape=(5,)
A.shape=(2, 1)
chosen_p_B.shape=(2, 1, 5)
Traceback (most recent call last):
File "<stdin>", line 6, in <module>
File "[...]/.venv/lib/python3.12/site-packages/numpyro/infer/util.py", line 751, in initialize_model
(init_params, pe, grad), is_valid = find_valid_initial_params(
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "[...]/.venv/lib/python3.12/site-packages/numpyro/infer/util.py", line 473, in find_valid_initial_params
(init_params, pe, z_grad), is_valid = _find_valid_params(
^^^^^^^^^^^^^^^^^^^
File "[...]/.venv/lib/python3.12/site-packages/numpyro/infer/util.py", line 459, in _find_valid_params
_, _, (init_params, pe, z_grad), is_valid = init_state = body_fn(init_state)
^^^^^^^^^^^^^^^^^^^
File "[...]/.venv/lib/python3.12/site-packages/numpyro/infer/util.py", line 443, in body_fn
pe, z_grad = value_and_grad(potential_fn)(params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "[...]/.venv/lib/python3.12/site-packages/numpyro/infer/util.py", line 325, in potential_energy
log_joint, model_trace = log_density_(
^^^^^^^^^^^^^
File "[...]/.venv/lib/python3.12/site-packages/numpyro/contrib/funsor/infer_util.py", line 329, in log_density
result, model_trace, _ = _enum_log_density(
^^^^^^^^^^^^^^^^^^
File "[...]/.venv/lib/python3.12/site-packages/numpyro/contrib/funsor/infer_util.py", line 298, in _enum_log_density
raise ValueError(
ValueError: Expected the joint log density is a scalar, but got (2,). There seems to be something wrong at the following sites: {'_pyro_dim_3'}.
The error message mentions this _pyro_dim_3 site that seems to be created by the enumeration procedure, so it doesn’t give me much information on how to proceed.
I’m sure there is something really obvious that I’m missing but I just can’t figure it out. Any pointers would be really appreciated.