probcomp / Venturecxx

Primary implementation of the Venture probabilistic programming system
http://probcomp.csail.mit.edu/venture/
GNU General Public License v3.0
29 stars 6 forks source link

log_joint_at crashes for nodes whose existence is conditional #211

Closed marcoct closed 8 years ago

marcoct commented 8 years ago
[assume mu (mem (lambda (j) (normal 0.0 10.0)))]
[assume z (mem (lambda (i) (uniform_discrete 0 2)))]
[observe (normal (mu (z 1)) 1.0) 0.321]
[infer global_log_joint]
Traceback (most recent call last):
  File "/usr/local/bin/venture", line 4, in <module>
    __import__('pkg_resources').run_script('venture==0.4.1.post313+ge9980af', 'venture')
  File "/usr/local/lib/python2.7/site-packages/pkg_resources/__init__.py", line 742, in run_script
    self.require(requires)[0].run_script(script_name, ns)
  File "/usr/local/lib/python2.7/site-packages/pkg_resources/__init__.py", line 1667, in run_script
    exec(code, namespace, namespace)
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/EGG-INFO/scripts/venture", line 178, in <module>
    lite(args)
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/EGG-INFO/scripts/venture", line 57, in lite
    local_ripl(args, v.Lite())
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/EGG-INFO/scripts/venture", line 61, in local_ripl
    (interactive, r, files, plugins) = build()
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/EGG-INFO/scripts/venture", line 86, in build
    r.execute_program_from_file(f)
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/ripl/ripl.py", line 284, in execute_program_from_file
    self.execute_program(f.read())
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/ripl/ripl.py", line 264, in execute_program
    return self.execute_parsed_program(*self.parse_program(program_string))
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/ripl/ripl.py", line 272, in execute_parsed_program
    vals.append(self.execute_instruction(instruction))
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/ripl/ripl.py", line 158, in execute_instruction
    self._raise_annotated(e, instruction)
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/ripl/ripl.py", line 154, in execute_instruction
    stringable_instruction)
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/ripl/ripl.py", line 170, in _execute_parsed_instruction
    return self.sivm.execute_instruction(parsed_instruction)
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/sivm/venture_sivm.py", line 69, in execute_instruction
    response = self._call_core_sivm_instruction(instruction)
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/sivm/venture_sivm.py", line 130, in _call_core_sivm_instruction
    response = self.core_sivm.execute_instruction(desugared_instruction)
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/sivm/core_sivm.py", line 46, in execute_instruction
    return f(instruction)
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/sivm/core_sivm.py", line 160, in _do_infer
    (did, val) = self.engine.infer(e)
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/engine/engine.py", line 234, in infer
    return self.raw_evaluate([v.sym("run"), program])
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/engine/engine.py", line 176, in raw_evaluate
    did = self._do_raw_evaluate(program)
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/engine/engine.py", line 184, in _do_raw_evaluate
    self.infer_trace.eval(did, program)
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/untraced/trace.py", line 53, in eval
    val = evaluator.eval(addr.Address(addr.List(id)), py_exp, self.env)
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/untraced/evaluator.py", line 54, in eval
    val = apply(address, nodes, env)
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/untraced/evaluator.py", line 78, in apply
    req_nodes = [evalRequest(req_args, spr, r) for r in requests.esrs]
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/untraced/evaluator.py", line 119, in evalRequest
    ans = node.Node(new_addr, eval(new_addr, r.exp, r.env))
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/untraced/evaluator.py", line 50, in eval
    v = eval(addr,subexp,env)
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/untraced/evaluator.py", line 54, in eval
    val = apply(address, nodes, env)
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/untraced/evaluator.py", line 80, in apply
    return applyPSP(spr.sp.outputPSP, OutputArgs(address, nodes[1:], env, req_nodes, requests))
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/untraced/evaluator.py", line 109, in applyPSP
    val = psp.simulate(args)
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/lite/psp.py", line 358, in simulate
    return self.f_type.wrap_return(self.psp.simulate(self.f_type.unwrap_args(args)))
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/lite/inference_sps.py", line 92, in simulate
    ans = getattr(engine, self.name)(*self.operands)
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/engine/inference.py", line 102, in log_joint_at
    return self.engine.model.traces.map('log_joint_at', scope, block)
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/multiprocess.py", line 201, in map
    return self.handle_result_list(res)
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/multiprocess.py", line 234, in handle_result_list
    raise exception_handler.gen_exception()
venture.exception.VentureException: *** evaluation: Cannot deterministically propose values for nodes whose existence is conditional
**************************************************
Stack trace from worker:
**************************************************
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/multiprocess.py", line 104, in wrapped
    res = f(*args, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/multiprocess.py", line 340, in <lambda>
    return safely(lambda *args,**kwargs: getattr(self.obj, attrname)(*args, **kwargs))
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/lite/trace.py", line 572, in log_joint_at
    registerDeterministicLKernels(self, scaffold, pnodes, currentValues)
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/lite/infer/mh.py", line 32, in registerDeterministicLKernels
    raise Exception("Cannot deterministically propose values for nodes whose existence is conditional")
Exception: Cannot deterministically propose values for nodes whose existence is conditional

(run global_log_joint)
^^^^^^^^^^^^^^^^^^^^^^
Caused by
Cannot deterministically propose values for nodes whose existence is conditional
**************************************************
Stack trace from worker:
**************************************************
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/multiprocess.py", line 104, in wrapped
    res = f(*args, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/multiprocess.py", line 340, in <lambda>
    return safely(lambda *args,**kwargs: getattr(self.obj, attrname)(*args, **kwargs))
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/lite/trace.py", line 572, in log_joint_at
    registerDeterministicLKernels(self, scaffold, pnodes, currentValues)
  File "/usr/local/lib/python2.7/site-packages/venture-0.4.1.post313+ge9980af-py2.7-macosx-10.9-x86_64.egg/venture/lite/infer/mh.py", line 32, in registerDeterministicLKernels
    raise Exception("Cannot deterministically propose values for nodes whose existence is conditional")
Exception: Cannot deterministically propose values for nodes whose existence is conditional
axch commented 8 years ago

There is a semantic logic to this problem. Imagine a model with an unknown number of continuous latents, like an uncollapsed DPMM with continuous cluster parameters. One might imagine computing the global posterior at any given configuration of parameters, but what does that actually mean? The number is a probability density, that must be interpreted with respect to something like counting measure on all the discrete variables and Lebesgue measure on the continuous ones. What would it mean to compare two such numbers, if the number of clusters is different? Formally, the "probability" of a (infinite-precision) configuration with more clusters is infinitely smaller than the "probability" of one with fewer. But the density in both cases is a finite number, and in fact, the information of how many Lebesgue-measured quantities were involved is lost by the time that number is presented.

What should global_log_joint to do in this circumstance?

(Note: global_log_likelihood remains sensible, because it's only the observations whose base measure is relevant, and that's presumably the same across all points of comparison.)

lenaqr commented 8 years ago

global_log_likelihood remains sensible

Well except when it already isn't. observe if (flip()) { uniform_continuous(0, 10) } else { uniform_discrete(0, 10) } = 5

marcoct commented 8 years ago

Despite the measure issues, it is possible to adapt the code to compute this quantity (each random choice can report its log probability (density) given its parents, plus global log likelihood) anyway, with a large warning in the documentation for this method indicating that results may be difficult to interpret or compare in certain cases?

Having this quantity, in addition to the global-log-likelihood, will help us to understand how our KL divergences and probability ratios compare to this quantity, and the semantic issues with this quantity may even be an important for highlighting the importance of using a technique like our KL-based measurement technique instead of log joint as a debugging tool.

Request: Create a second version of global_log_joint that has a scary sounding name like unsafe_global_log_joint (to discourage casual use) that doesn't crash when it encounters measure-theoretic problems.

axch commented 8 years ago

The structural problem is that regen and detach autmatically repropose brush from from the prior, and do not compute the weight.

Ways this request could be satisfied anyway:

Issues

Details, if adopting the custom proposal plan

axch commented 8 years ago

@riastradh-probcomp, could you implement this? If the above discussion is not enough to go on, we can talk about it.

axch commented 8 years ago

Fixed by #572.