Open ngoodman opened 6 years ago
This issue I reported on the probmods page may also be relevant:
https://github.com/probmods/probmods2/issues/55
my workaround using cache
suggests that the semantics for cache
are perhaps also not quite working as intended (the documentation suggests that cache
should be fully deterministic, but current functioning appears to be consistent with Noah's description of the Church mem
semantics above).
I don't have any good ideas about how to fix this at the moment, but here are a few thoughts on earlier comments:
in webppl it seems that we are breaking this convention, at least when a memoized function crosses an Infer boundary.
@ngoodman is right about the significance if the Infer
boundary. This arises because mem
is implemented by memoizing the function using WebPPL's global store as a cache. I think this is fine for the case of a single Infer
, but in the nested example the result of calling memfn('a')
is not automatically shared across executions of the inner model, because Infer
arranges for each such execution to have a fresh store.
Adding the call to memfn('a')
in the outer model adds the result to the cache before entering Infer
, which means that all executions of the inner model see it. (Since each execution of a model by Infer
sees the store as it was when Infer
was called.)
(the documentation suggests that cache should be fully deterministic, but current functioning appears to be consistent with Noah's description of the Church mem semantics above).
@daphnab It seems there may be some confusion here. The docs are trying to say that cache
should only be applied to a deterministic function. If cache
is applied to a stochastic function, all bets are off. For example, the use of cache
in this model causes exhaustive enumeration to produce different results depending on the strategy used:
var model = function() {
var f = cache(function() { return flip(); })
return [f('a'), f('b')].join(',')
}
Infer({model, method: 'enumerate', strategy: 'depthFirst'})
// Depth first:
// Marginal:
// "true,true" : 0.5
// "false,false" : 0.25
// "false,true" : 0.25
// Breadth first:
// Marginal:
// "true,true" : 0.25
// "true,false" : 0.25
// "false,true" : 0.25
// "false,false" : 0.25
If cache
is replaced with mem
in the above, then all strategies return the expected distribution.
I imagine that cache
only appears to have the desired mem
semantics for algorithms that always re-run the entire model, and that when the algorithm uses fancier control flow that will break down.
@null-a thanks for the clarification about cache
! In that case, is there currently a way to make an embedded non-parametric inference (as in the original inference about inference chapter examples)? The current work around in the chapter solves the issue by evaluating the a priori likeliest values outside the inner inference (so it's technically not quite correct, since a priori low probability sequences will still not have consistent probabilities assigned to them). My only other solution was to implement my own rejection sampling rather than using Infer
but that's obviously also quite limited.
is there currently a way to make an embedded non-parametric inference
@daphnab I don't have anything better than your solution at the moment I'm afraid.
i worked around this in ch6 of probmods, by getting rid of mem
.
at some point we should find a solution, though this is a pretty unused corner case....
i think there may be a bug, or at least questionable choice in the semantics of mem. consider:
different results are obtained if the
memfn('a');
line is uncommented. it does not seem to me like this should happen.the semantics we converged on for mem in Church was that all of the random sampling (for all inputs to the function) was to be considered as happening where the memoized function was created, even if the sampling was deferred in practice. in webppl it seems that we are breaking this convention, at least when a memoized function crosses an Infer boundary.
(this bug came to light in https://github.com/probmods/probmods2/pull/56)