pymc-devs / pymc

Bayesian Modeling and Probabilistic Programming in Python
https://docs.pymc.io/
Other
8.71k stars 2.01k forks source link

DOC: Provide a working example of inheriting from pymc.Model #6715

Closed galenseilis closed 4 months ago

galenseilis commented 1 year ago

Issue with current documentation:

The documentation for pymc.Model seems to give some conceptual gist of how it works, but the example given in the documentation does not work.

There are no imports, and I am not sure where pt is coming from in pt.constant(1). I have thought maybe pt was for "PyTensor" but there is no constant in the namespace of pt resulting from import pytensor as pt. There is a pymc.math.constant, but I am unsure if that is the same thing.

But it is also unclear if the imports are the only issue. Here is some code where I have attempted to address the above namespace issues.

from pymc import *

class CustomModel(Model):
    # 1) override init
    def __init__(self, mean=0, sigma=1, name=''):
        # 2) call super's init first, passing model and name
        # to it name will be prefix for all variables here if
        # no name specified for model there will be no prefix
        super().__init__(name, model)
        # now you are in the context of instance,
        # `modelcontext` will return self you can define
        # variables in several ways note, that all variables
        # will get model's name prefix

        # 3) you can create variables with the register_rv method
        self.register_rv(Normal.dist(mu=mean, sigma=sigma), 'v1', initval=1)
        # this will create variable named like '{name::}v1'
        # and assign attribute 'v1' to instance created
        # variable can be accessed with self.v1 or self['v1']

        # 4) this syntax will also work as we are in the
        # context of instance itself, names are given as usual
        Normal('v2', mu=mean, sigma=sigma)

        # something more complex is allowed, too
        half_cauchy = HalfCauchy('sigma', beta=10, initval=1.)
        Normal('v3', mu=mean, sigma=half_cauchy)

        # Deterministic variables can be used in usual way
        Deterministic('v3_sq', self.v3 ** 2)

        # Potentials too
        Potential('p1', pt.constant(1))

# After defining a class CustomModel you can use it in several
# ways

# I:
#   state the model within a context
with Model() as model:
    CustomModel()
    # arbitrary actions

# II:
#   use new class as entering point in context
with CustomModel() as model:
    Normal('new_normal_var', mu=1, sigma=0)

# III:
#   just get model instance with all that was defined in it
model = CustomModel()

# IV:
#   use many custom models within one context
with Model() as model:
    CustomModel(mean=1, name='first')
    CustomModel(mean=2, name='second')

# variables inside both scopes will be named like `first::*`, `second::*`

Running the above I get an AttributeError that I don't think is related because it occurs at super().__init__(name, model).

Traceback (most recent call last):
  File "/usr/lib/python3.10/idlelib/run.py", line 578, in runcode
    exec(code, self.locals)
  File "/home/galen/pymc_inheritance_question.py", line 42, in <module>
    CustomModel()
  File "/home/galen/.local/lib/python3.10/site-packages/pymc/model.py", line 264, in __call__
    instance.__init__(*args, **kwargs)
  File "/home/galen/pymc_inheritance_question.py", line 10, in __init__
    super().__init__(name, model)
  File "/home/galen/.local/lib/python3.10/site-packages/pymc/model.py", line 588, in __init__
    self.add_coords(coords)
  File "/home/galen/.local/lib/python3.10/site-packages/pymc/model.py", line 1080, in add_coords
    for name, values in coords.items():
AttributeError: 'Model' object has no attribute 'items'

Idea or request for content:

Please provide a minimum working example.

welcome[bot] commented 1 year ago

Welcome Banner :tada: Welcome to PyMC! :tada: We're really excited to have your input into the project! :sparkling_heart:
If you haven't done so already, please make sure you check out our Contributing Guidelines and Code of Conduct.

twiecki commented 1 year ago

@galenseilis Thanks for reporting, that definitely should be fixed (pt is import pytensor.tensor as pt). But I'd also like to know if what you're trying to do really requires this?

galenseilis commented 1 year ago

@twiecki Thank you for the clarification on pt.

Goals

Sure, let us start with clarifying what I am trying to do. I have three goals. They're sequentially-dependent in the sense that achieving goal 3 depends on achieving goal 2 which depends on achieving goal 1. However, it would still count for something if I achieved goal 1 alone, or only goal 1 and goal 2.

image

Goal 1

The first is just to understand how it works, unconditioned on "trying to do something else". Is a working example required to understand how pymc.Model works? Maybe not, but I recommend it.

image

Goal 2

The second goal is to understand where I might use it. What is the use case for making a PyMC model this way? Often a tool is created for a desired set of use cases, and I would like to understand what was the desired use case for being able to build models this way. Is a working example required to understand the use cases of inheriting from pymc.Model? Maybe not, but I recommend it.

image

Goal 3

The third goal is assess whether it is suitable for a project I am at the product design stage of. The concept is a Python package for random graphs, random hypergraphs, and random simplicial complexes among other things. PyMC is one of the tools I am considering for providing the Monte Carlo methods. If I go with PyMC, I want to make a decision about my model classes inheriting from pymc.Model exor using the usual context wrapper within my classes' __init__ to store the PyMC model as an attribute. Whether I subclass or use the context wrapper will depend on what I learn from goals 1 and 2. Is a working example required to understand what subclassing from pymc.Model would look like in my project? Maybe not, but I recommend it.

image

twiecki commented 1 year ago

Maybe https://github.com/pymc-devs/pymc-experimental/blob/main/pymc_experimental/model_builder.py#L30 could help you?

galenseilis commented 1 year ago

Maybe https://github.com/pymc-devs/pymc-experimental/blob/main/pymc_experimental/model_builder.py#L30 could help you?

That looks potentially useful for developing NetMC. Certainly something to weigh against in goal 3. If there are alternatives to pymc.Model I should consider them.

thodson-usgs commented 6 months ago

model_builder.py is interesting, but has that stalled?

It would be nice to know some conventions for instantiating complex models, but when I look to the doc, I always come back to the same broken example.

If there are no desire to fix it, could we/I at least remove the example?

twiecki commented 6 months ago

Didn't know it was broken?