DOC: Provide a working example of inheriting from pymc.Model
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.
: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.
@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?
@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.
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.
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.
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.
Maybe https://github.com/pymc-devs/pymc-experimental/blob/main/pymc_experimental/model_builder.py#L30 could help you?
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.
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?
Didn't know it was broken?