Equvilant APIs in PyMC v4


i was going through the example notebook Variational Inference: Bayesian Neural Networks since the VI APIs are available in pymc v4. i’ve noticed that the notebook utilized neural_network.out.distribution.p in cell In[11]. but i think that API is deprecated in v4 and/or aesara? the error message was:

AttributeError: 'TensorVariable' object has no attribute 'distribution'

i’ve crawled through this discussion and the release note, but failed to identify documentation on such topic… or perhaps wasn’t familiar with pymc enough to identify. please direct me to docs/discussions on the subject and the correct API i should adopt to the notebook.

a prior thanks.

1 Like

How did you install v4? The v4 update to VI was only merged last week (if I remember correctly) and is thus not available in the current beta.

well I used editable install in order to try out the new feature.

I know that the FreeRV stuff has changed with v4. @twiecki, it’s was your post originally.

I have a very related issue currently. I am porting a causal model from pymc3 to pymc4 and I’ve previously used the following code to check if a variable is a categorical:

def is_categorical(variable):
    return hasattr(variable, "distribution") and isinstance(
        variable.distribution, pm.Categorical

Unfortunately, this does not seem to work any longer in pymc4. Can anyone help me to find an alternative that will work?

1 Like

For simple distributions you can do this:

import pymc as pm

x = pm.Categorical.dist([0.5, 0.5])
isinstance(x.owner.op, pm.Categorical)

In the very next release of V4 you will be able to do this for all distributions (Mixture fails with the previous approach):

import pymc as pm

x = pm.Categorical.dist([0.5, 0.5])
isinstance(x.owner.op, pm.Categorical.rv_type)
1 Like

This solved my issue

Thank you @ricardoV94 !

I stumbled upon a very related issue. In pymc3 we were able to access the number of categories in the x ~ pm.Categorical via

num_categories = x.distribution.k.tolist()

I came up with a hacky way to achieve this in pymc4 (via x.owner.inputs) but I am wondering if you could tell me a better way to achieve this @ricardoV94 ?

Here’s what I’m doing

diris = [input for input in x.owner.inputs if is_dirichlet(input)]
assert len(diris) == 1, "There should be exactly 1 Dirichlet input for a categorical variable"
num_categories_common_cause = [0].shape.eval()[0]

which works, since our pm.Categorical(name, p=p) variables always take a p ~ pm.Dirichlet

You don’t need to iterate over the inputs, the p parameter will always be x.owner.inputs[3]. Otherwise that should be fine as long as p has a fixed length. I think we do the same internally here: pymc/metropolis.py at main · pymc-devs/pymc · GitHub

And this is the approach suggested in the comment: pymc/metropolis.py at main · pymc-devs/pymc · GitHub

I see. Thank you

And you should check shape[-1], just in case you have a batched Categorical RV

1 Like

Looking at the CategoricalGibbsMetropolis code, it seems like I also don’t actually need to use .eval() ?

That’s just another way of evaling. A function is still compiled and evaluated. If you want something that does not involve compilation you can try this strategy instead: pymc/timeseries.py at main · pymc-devs/pymc · GitHub