Repository navigation
BUG: finite gradients of the log densities outside the support - #151
Merged
Merged
Conversation
With jax, the gradient of jnp.logaddexp(-inf, -inf) is nan, so the gradient of every log-space mixture with respect to its mixing fraction was nan whenever a sample is outside the support of every component, e.g., below mmin: ln_two_component_single and the models built on it, ln_three_component_single, ln_double_power_law_peak_primary_mass (where the nan also reached every power-law parameter) and ln_independent_spin_orientation_gaussian_isotropic. This breaks gradient-based samplers, e.g., NUTS, using the log density. - utils.logaddexp: with jax, both terms are replaced by zero where both are -inf before calling xp.logaddexp, and its result by -inf after, so the gradient there is zero. Used by every mixture. - BaseSmoothedMassDistribution.ln_p_q: the log of one, rather than of zero, where the mass ratio normalization vanishes (m1 < mmin), which gave nan gradients with respect to beta, mmin and delta_m. - ln_beta_dist: one in place of scale - xx above the support, which gave nan gradients with respect to beta for spin magnitudes above amax, also for beta_dist. The values are unchanged: bit-identical for every model with numpy and with jit-compiled jax in double precision. In single precision under jit, XLA fuses ln_two_component_single differently, changing values at the level of float32 rounding (at most 4e-6) with the same accuracy. test_ln_prob_gradient checks that the gradient of the log of the summed density with respect to every hyperparameter, with samples outside the support, is finite in single and double precision and, in double precision, matches the gradient computed from the density wherever that is finite. Still not finite: the derivative with respect to a mixing fraction of exactly zero or one in log space, and the gradients of the linear smoothed models' p_q with respect to beta, mmin and delta_m. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #151 +/- ##
==========================================
+ Coverage 95.61% 95.64% +0.03%
==========================================
Files 14 14
Lines 1252 1261 +9
==========================================
+ Hits 1197 1206 +9
Misses 55 55
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
With jax, the gradient of
jnp.logaddexp(-inf, -inf)isnan. Every log-space mixture combines its components aslogaddexp(log1p(-lam) + ln_a, log(lam) + ln_b), so the gradient with respect to the mixing fraction wasnanas soon as any sample was outside the support of every component, e.g.,mass_1 < mmin, which is common for PE samples. Forln_double_power_law_peak_primary_massthenanalso reached every power-law parameter. This breaks NUTS and other gradient-based samplers usingln_prob;ln_two_component_singleandln_two_component_primary_mass_ratiohave had it since #144.Changes
utils.logaddexp: with jax, both terms are replaced by zero where both are-infbefore callingxp.logaddexp, and its result by-infafter, so the gradient there is zero (numpy and cupy callxp.logaddexpdirectly). Used by every mixture:_ln_two_component_single,ln_three_component_single,ln_double_power_law_peak_primary_massandln_independent_spin_orientation_gaussian_isotropic. Thelogaddexp(0.0, x)calls in the smoothing window and Madau-Dickinson are already safe.BaseSmoothedMassDistribution.ln_p_q: the log of one, rather than of zero, where the mass ratio normalization vanishes (m1 < mmin), which gavenangradients with respect tobeta,mminanddelta_mfor every smoothed and spline mass model.ln_beta_dist: one in place ofscale - xxabove the support, which gavenangradients with respect tobetafor spin magnitudes aboveamax(also forbeta_dist, which is its exponential).Gradients
jax.gradoflogsumexp(ln_prob)with respect to every hyperparameter, for every model intest/ln_model_test.py(10 draws, its dataset with samples outside the support):nan:lam,lam_1(all parameters for the broken power law + peak)nan:beta,mmin,delta_m(andlam,lam_1with peaks)nan:beta_chiIn double precision, the gradients match those computed from the linear density to ~1e-11 (relative) wherever the latter are finite. In single precision, the log-space gradients are finite for every model, while the linear ones overflow for steep power laws.
Values
Unchanged: bit-identical for every model with numpy and with jit-compiled jax in double precision. In single precision under jit, XLA fuses
ln_two_component_singledifferently, which changes values at the level of float32 rounding (at most 4e-6 on the test draws) with the same accuracy against double precision. The guard inln_beta_distis onscale - xxonly: guardingxxtoo moveslog(xx)from compile time (XLA constant-folds the logs of closed-over data) to run time and changes single precision rounding.No measurable change in the speed of the jitted log density or its gradient.
Tests
test_ln_prob_gradientchecks, for every model in single and double precision, that this gradient is finite and, in double precision, that it matches the gradient computed from the density wherever that is finite. It uses 3 draws per model; its run time is dominated by compiling the two gradients and the first (eager) call per model, not the draws. Without the source changes, 26 of its 60 cases fail. The full suite passes on CPU with jax 0.12 (460 passed, 2 skipped), where the new test takes ~40 s.Still not finite
log(0)); the linear density's is finite. This would need a custom derivative.p_qwith respect tobeta,mminanddelta_m. Dividing bywhere(norm > 0, norm, 1)fixes most, but not all, of the test draws.🤖 Generated with [Cl