Skip to content
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

Refactor distribution.draw_values #2902

Merged
merged 12 commits into from
Mar 21, 2018
Merged

Refactor distribution.draw_values #2902

merged 12 commits into from
Mar 21, 2018

Conversation

lucianopaz
Copy link
Contributor

This solves issue #2900.
Just two things were changed:

  1. distribution.draw_values
  2. model.get_named_nodes

The problem occured in automatically transformed RVs because the corresponding free RV (for example, a would be the TransformedRV and a_log__ the FreeRV) was interpreted as input to the TransformedRVand at the same time, lacked a random method. When trying to draw a sample from a, which did define random, draw_value would raise a theano.gof.fg.MissingInputError because it first tried to call _draw_value for a_log__.

To cope with this possibility, instead of searching only for the leaf named nodes, like the original model.get_named_nodes function did, we get the leaf nodes, and also the parent/child relations between named nodes. The new function that does this is model.get_named_nodes_and_relations. draw_value now first tries to _draw_value from the leaf nodes but if this fails, it attempts to do the same on that node's parents. If _draw_value succeeds on the parent, its value is passed to givens. The rest of the execution is the same.

@lucianopaz
Copy link
Contributor Author

After submitting the pull request #2902, I noticed that the travis testsuite was failing. The only test that failed was pymc3.tests.test_random.TestDrawValues().test_dep_vars(), which I should have foreseen because it explicitly tests to see if theano.gof.MissingInputError gets raised. Sorry for missing that.

I changed the test now to check that it is possible to make successful calls to draw_values even in the case of having dependent variables.

Copy link
Member

@junpenglao junpenglao left a comment

Choose a reason for hiding this comment

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

Thanks! I think it looks nice and it will make draw_values much easier to use.

@@ -230,16 +230,65 @@ def draw_values(params, point=None):
"""
# Distribution parameters may be nodes which have named node-inputs
# specified in the point. Need to find the node-inputs to replace them.
givens = {}

# Issue #2900 describes a situation in which, the named node-inputs
Copy link
Member

Choose a reason for hiding this comment

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

This information is too detailed here. It is better to put into the release note.

val2 = draw_values([a], point={'sd_log__': np.array([2., 3.])})[0]
assert np.all(val1 != val2)
# After #2900 theano.gof.MissingInputError should not be raised
# with a plain draw_values
Copy link
Member

Choose a reason for hiding this comment

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

I dont think we need comments here.

@lucianopaz
Copy link
Contributor Author

@junpenglao, thanks for the comments. I'll fix those parts of the code, but first I'll try to find the bug that is making the tests fail on travis. Apparently it has something to do with memoize, that changes params type but I'm having trouble fixing it. I hope to be able to sort it out on monday.

…ent to RELEASE-NOTES. Fixed bug in the interaction between draw_values, _draw_value and _compile_theano_function. In some cases, draw_values would set an item of the givens dictionary to a theano.tensor.TensorConstant. In _draw_value(param, ...), if param was a theano.tensor.TensorVariable without a random method, and not set in point, _compile_theano_function would be called, using as one of its variables, a theano.tensor.TensorConstant. This lead to TypeError: ("Constants not allowed in param list",...) exceptions being raised. The fix was to skip the inclusion into the givens dictionary of named nodes that were instances of theano.tensor.TensorConstant, because their value would already be available for theano during the function compilation.
@junpenglao junpenglao added the WIP label Mar 20, 2018
…nt, but it occurred on theano.tensor.sharedvar.SharedVariable instances. The error that was raised was similar, SharedVariables cannot be supplied as raw input to theano.function. The fix was the same as for TensorConstants, skip them when constructing the givens dictionary.
@lucianopaz
Copy link
Contributor Author

@junpenglao, I think that I finally routed out the bug that made the tests fail in the CI. The problem was that in some cases, draw_values would set an item of the givens dictionary to a theano.tensor.TensorConstant or a theano.tensor.sharedvar.SharedVariable. Later, in _draw_value(param, ...), if param was a theano.tensor.TensorVariable without a random method, and not set in point, _compile_theano_function would be called, using as one of its input variables, a theano.tensor.TensorConstant or a theano.tensor.sharedvar.SharedVariable. This lead to TypeError: ("Constants not allowed in param list",...) or TypeError: Cannot use a shared variable (...) as explicit input. exceptions being raised. The fix was to skip the inclusion into the givens dictionary of named nodes that were instances of theano.tensor.TensorConstant or theano.tensor.sharedvar.SharedVariable, because their value would already be available to theano during the function compilation.

…nsorConstant and SharedVariable types, these nodes could be added to the stack again later because their names would not be in givens.keys(). To counter that, a separate set, `stored`, with the names of nodes that are either stored in givens or whos values should be available to theano.function, is used to chose which nodes to add to the stack.
@@ -260,13 +260,17 @@ def draw_values(params, point=None):
if next_ in givens.keys():
# If the node already has a givens value, skip it
continue
elif isinstance(next_, theano.tensor.TensorConstant):
# If the node is a TensorConstant, its value will be
elif isinstance(next_, tt.TensorConstant) or \
Copy link
Member

Choose a reason for hiding this comment

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

isinstance(next_, (tt.TensorConstant, tt.sharedvar.SharedVariable))

@twiecki
Copy link
Member

twiecki commented Mar 21, 2018

LGTM, waiting for @junpenglao to merge.

@junpenglao junpenglao merged commit f833a14 into pymc-devs:master Mar 21, 2018
@junpenglao
Copy link
Member

Well done @lucianopaz !!! And congrats on the first contribution ;-)

@twiecki twiecki removed the WIP label Mar 21, 2018
@lucianopaz
Copy link
Contributor Author

Thanks! I'm glad I could contribute!

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.

3 participants