Skip to content

Set theano config in model context #2103

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 8, 2017
Merged

Conversation

aseyboldt
Copy link
Member

This should fix #566. I'm not sure this is the best way to do this, it might be better to include the theano context in Context, but this gets a bit complicated because we need to pass arguments though metaclasses and multiple inheritance.
I removed sum_div_dimshuffle_bug. Couldn't even find a reference to this in the theano config. I guess this was removed at some point?
I set compute_test_value to 'ignore' in some functions about the hessian, because I had some trouble with those (see Theano/Theano#5907).

@twiecki
Copy link
Member

twiecki commented May 1, 2017

Nice, this one was bothersome for quite some time, thanks for taking this on. I like the approach.

@ferrine
Copy link
Member

ferrine commented May 1, 2017

I strongly support this PR. That's the thing that always annoys

pymc3/model.py Outdated

def __enter__(self):
# __enter__ is called by InitContextMeta before __init__
if hasattr(self, '_theano_config'):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No check on exit. Do you really need it?

Copy link
Member

@ferrine ferrine May 2, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If config is set in __new__ this code can be omitted. Attribute will be already set

pymc3/model.py Outdated
@@ -434,6 +439,23 @@ def __init__(self, name='', model=None):
self.potentials = treelist()
self.missing_values = treelist()

if theano_config is None:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point having this check. I would also force testvalue in dict

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean adding the testval option even when a config dict is specified? I guess we could add it if it is not already in there, I'm not sure about this though.

pymc3/model.py Outdated
self._theano_config = theano.configparser.change_flags(**theano_config)
# We need to enter the theano config, since variables could be
# created in the init of subclasses.
self._theano_config.__enter__()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You do not need it. Init is done in modelcontext

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think I do. The problem is that subclasses of Model are allowed to add variables in __init__, so __enter__ is called before Model.__init__ using some metaclass magic. But maybe it would be better to move this to the metaclass instead of doing it in init.

Copy link
Member

@ferrine ferrine May 2, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm I see the problem now. Yes, It can be done in __new__(here), that's the best place for setting config.

@aseyboldt
Copy link
Member Author

change_flags from theano can't be pickled, because of the usage of nested functions. I wrote a similar function in pymc3.theanof that doesn't have this problem, but I had to use some more internal functionality from theano. If nobody has objections to that, this should be ready to merge (if the tests...)

@aseyboldt
Copy link
Member Author

@ferrine The config is set in __new__ now.

@ferrine
Copy link
Member

ferrine commented May 7, 2017

Let's wait for tests

@aseyboldt aseyboldt force-pushed the fix-566 branch 2 times, most recently from 602a299 to 81e7bcd Compare May 7, 2017 22:05
@twiecki
Copy link
Member

twiecki commented May 8, 2017

==================================== ERRORS ====================================
__________________ ERROR collecting pymc3/tests/test_step.py ___________________
self = <pymc3.tests.test_step.TestStepMethods object at 0x7ff75c0b4b90>
    def test_step_elliptical_slice(self):
        start, model, (K, L, mu, std, noise) = mv_prior_simple()
        unc = noise ** 0.5
        check = (('x', np.mean, mu, unc / 10.),
                 ('x', np.std, std, unc / 10.))
        with model:
            steps = (
                EllipticalSlice(prior_cov=K),
                EllipticalSlice(prior_chol=L),
            )
        for step in steps:
>           trace = sample(5000, step=step, start=start, model=model, random_seed=1)
pymc3/tests/test_step.py:241: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
pymc3/sampling.py:260: in sample
    return sample_func(**sample_args)
pymc3/sampling.py:275: in _sample
    for it, strace in enumerate(sampling):
../../../miniconda2/envs/testenv/lib/python2.7/site-packages/tqdm/_tqdm.py:833: in __iter__
    for obj in iterable:
pymc3/sampling.py:377: in _iter_sample
    point = step.step(point)
pymc3/step_methods/arraystep.py:119: in step
    apoint = self.astep(bij.map(point), *inputs)
pymc3/step_methods/elliptical_slice.py:91: in astep
    chol = draw_values([self.prior_chol])
pymc3/distributions/distribution.py:190: in draw_values
    param, point=point, givens=givens.values()))
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
param = Cholesky{lower=True, destructive=False, on_error='raise'}.0
point = None, givens = []
    def draw_value(param, point=None, givens=()):
        if hasattr(param, 'name'):
            if hasattr(param, 'model'):
                if point is not None and param.name in point:
                    value = point[param.name]
                elif hasattr(param, 'random') and param.random is not None:
                    value = param.random(point=point, size=None)
                else:
                    value = param.tag.test_value
            else:
                input_pairs = ([g[0] for g in givens],
                               [g[1] for g in givens])
    
                value = _compile_theano_function(param,
                                                 input_pairs[0])(*input_pairs[1])
        else:
            value = param
    
        # Sanitising values may be necessary.
        if hasattr(value, 'value'):
            value = value.value
        elif hasattr(value, 'get_value'):
            value = value.get_value()
    
        if hasattr(param, 'dtype'):
            value = np.atleast_1d(value).astype(param.dtype)
        if hasattr(param, 'shape'):
            try:
                shape = param.shape.tag.test_value
            except:
                shape = param.shape
>           if len(shape) == 0 and len(value) == 1:
E           TypeError: object of type 'TensorVariable' has no len()
pymc3/distributions/distribution.py:253: TypeError

@aseyboldt
Copy link
Member Author

@twiecki The problem were the tests generated by yield. The generators were executed before the fixture that sets compute_test_value. I turned them into ordinary tests, as yield-tests are deprecated anyway. This also speeds up test discovery.

@twiecki
Copy link
Member

twiecki commented May 8, 2017

Sounds good.

@twiecki twiecki merged commit 4822cf0 into pymc-devs:master May 8, 2017
@twiecki
Copy link
Member

twiecki commented May 8, 2017

Thanks @aseyboldt, great to finally have this issue resolved.

@krishnbera
Copy link

I am trying to set theano.config.compute_test_value="warn" but I don't know how to specify this in PyMC3.
I tried using pymc3.theanof.set_theano_conf({'compute_test_value':'warn'}) but that doesn't work. After setting this, when I print the value of compute_test_value, it returns raise. What is the correct way of specifying it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Don't set compute_test_value to raise
4 participants