-
Notifications
You must be signed in to change notification settings - Fork 10
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
Handle NaN gracefully in sampler.MarkovChain #69
Conversation
@fredRos Bump :-) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For me , it was always useful to bail out on NaN because our target density shouldn't return that. You can always wrap your target function to catch NaN, so I am not sure this change is really needed. What is your use case that NaN is an OK value for the target density?
pypmc/sampler/markov_chain.py
Outdated
else: | ||
this_run[i_N] = self.current_point | ||
#do not need to update self.current | ||
#self.current = self.current |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove commented code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
pypmc/sampler/markov_chain.py
Outdated
#self.current = self.current | ||
else: | ||
# accept if rho = 1 | ||
if log_rho >=0: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How could I allow this code duplication? All of this should disappear and we can just check for log_rho >= _np.log(self.rng.rand())
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer if we deduplicated code in a separate commit, or not at all. It is very readable in this way. But it's your decision in the end!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, it comes to mind that your proposed condition changes the number of evaluations of rng
. Would make old computation non-repeatable. This is not the case for my changes, since previous computations would simply fail.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I vaguely remember we used to do something different in the two branches but we don't anymore. Yep, it's a different issue. So let's leave as is. And good point about rng evaluation. Easily solved with short-circuit semantics
if log_rho >=0 or log_rho >= _np.log(self.rng.rand()):
In my case I run into edges of the parameter space in which the target density is not defined. I cannot easily cut these regions out, since the boundaries of the parameter space cannot be determined analytically.
Yes, but then I need to assign a regular value for the target density instead, with a non-zero probability that the Markov chain accepts it nevertheless. In this way, I can reject the invalid point entirely and deterministically.
It's a light-cone sum rule calculation in EOS. The likelihood contains observables that are ill defined in a pocket of the (30dim) parameter space. I'd also like to add that the PMC sample continues on NaN in the target density. Changing this here make both samplers work for the same set of target densities. |
On 28.09.20 10:10, Danny van Dyk wrote:
For me , it was always useful to bail out on NaN because our
target density shouldn't return that.
In my case I run into edges of the parameter space in which the target
density is not defined. I cannot easily cut these regions out, since
the boundaries of the parameter space cannot be determined analytically.
You can always wrap your target function to catch NaN, so I am not
sure this change is really needed.
Yes, but then I need to assign a regular value for the target density
instead, with a non-zero probability that the Markov chain accepts it
nevertheless. In this way, I can reject the invalid point entirely and
deterministically.
Not really: I always had my density return '-numpy.inf' in that case
since Limit[x-->0, x>0] log(x) = -infinity. Note that minus infinity is
(at least was when I was actively working on pypmc) handled correctly
and this is also how the builtin indicator functions are implemented.
…
What is your use case that NaN is an OK value for the target density?
It's a light-cone sum rule calculation in EOS. The likelihood contains
observables that are ill defined in a pocket of the (30dim) parameter
space.
I'd also like to add that the PMC sample continues on NaN in the
target density. Changing this here make both samplers work for the
same set of target densities.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#69 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/ABNC62LA3TFB7BSX7QTTRH3SIBAFVANCNFSM4OKAEEIQ>.
|
Yes, I agree with @jPhy that
Good point. Should create a separate issue for that. I don't know if the update equations are correct with nan values.
I see. In the end, it boils down to a question of convenience. What should happen and who has control. You might just want to continue, and could just return -inf instead of NaN. Another use might want to count the NaNs, or log a message or raise a different kind of exception. So I think the best solution is to leave this in the hands of the user. The other question is: is it a good idea to raise an exception by default? I think yes because at some point I didn't have this check in there and then the output of the chain was not from the target density because some checks failed as NaN comparisons come out |
@dvandyk I thought about it. In terms of customer orientation, I'm happy to make that little change if it makes life easier for you. If you or anyone else wants more control over handling NaNs, that should be done in the client code; i.e. outside pypmc |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nearly done, only cosmetics left
pypmc/sampler/markov_chain.py
Outdated
#self.current = self.current | ||
else: | ||
# accept if rho = 1 | ||
if log_rho >=0: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I vaguely remember we used to do something different in the two branches but we don't anymore. Yep, it's a different issue. So let's leave as is. And good point about rng evaluation. Easily solved with short-circuit semantics
if log_rho >=0 or log_rho >= _np.log(self.rng.rand()):
pypmc/sampler/markov_chain.py
Outdated
@@ -107,6 +107,11 @@ def run(self, N=1): | |||
|
|||
An int which defines the number of steps to run the chain. | |||
|
|||
:param continue_on_NaN: | |||
|
|||
A boolean flag defining the behaviour when encountering an NaN. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A boolean flag defining the behaviour when encountering an NaN. | |
A boolean flag defining the behavior when encountering an NaN in the user-supplied target density for a proposed point. |
pypmc/sampler/markov_chain.py
Outdated
:param continue_on_NaN: | ||
|
||
A boolean flag defining the behaviour when encountering an NaN. | ||
Default: False (-> raise ValueError) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Default: False (-> raise ValueError) | |
Default: ``False`` (-> raise ``ValueError``). If ``True``, reject the proposed point and continue. |
pypmc/sampler/markov_chain.py
Outdated
# reject if not accepted | ||
else: | ||
if _np.isnan(log_rho): | ||
# raise error if so desired |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
useless comment. Please remove
@dvandyk THere were only small things left on this PR, let's take it over the finish line |
@dvandyk Friendly ping |
…ampling with Markov chains Reviewed-by: Frederik Beaujean <beaujean@mpp.mpg.de>
Sorry for the delay, here it is! |
passed tests https://travis-ci.org/github/fredRos/pypmc/builds/759851896, well done! |
Lieber Fred,
I sometimes encounter NaNs in the log(target) in corners of the parameter space. It would be very helpful, if this modification or something similar to it could end up in a released version of
pypmc
.I am also happy to change the name of the keyword argument if you disagree. I had considered e.g.
ignore_NaN
. Let my know what you think!Cheers
Danny