Repository navigation
fix(distributions): keep Cauchy and StudentT log_prob finite for very large values - #2341
yupengtang wants to merge 1 commit into
Conversation
… large values log1p(z ** 2) overflowed once |z| passed about 1.8e19 in float32, giving -inf and a zero gradient. Use 2 * log(hypot(1, z)) instead.
|
I don't think these AI generated PRs are very useful as they introduce us hard to read at the expense of these unreasonable outliers. If you have not suffer from these overflows in a model, my suggestion is to close this (and all future PRs) |
|
Im also not fond of "AI assistance: I used Claude Code to find this, with the same scipy comparison sweep" as this increases maintenance burden. IMO these AI scans PRs should be blocked. |
Benchmark reportthis PR - run time: 2 slower, 1 faster
compile time: unchanged across 32 benchmarksSignificant changes (3) ──────── run time ─────── ───── compile time ─────
benchmark baseline this PR Δ baseline this PR Δ
─────────────────────────────────────────────────────────────────────────────────
+ categorical_log_prob 1.2 ms 1.2 ms -6.0% 47.6 ms 52.1 ms +9.5%
- nuts_eight_schools 802.9 ms 847.0 ms +5.5% 1.72 s 1.85 s +7.5%
- nuts_vectorized_chains 1.75 s 1.86 s +6.5% 1.96 s 1.93 s -1.9%Red is slower, green is faster; a row is coloured by the worse of its two columns. A delta in parentheses cleared the threshold on a measurement below the resolution floor, so it is shown without being called a change. † marks a benchmark that could not be compared — see below. Full results
|
| baseline | this PR | |
|---|---|---|
| ref | master |
fix-cauchy-studentt-log-prob-tails |
| commit | 31dcd985 |
e4474b2b |
| numpyro | 0.22.0 | 0.22.0 |
| jax | 0.11.2 | 0.11.2 |
| backend | cpu | cpu |
| python | 3.14.8 | 3.14.8 |
Runner: Linux-6.17.0-1022-azure-x86_64-with-glibc2.39, 4 CPUs.
Produced by this benchmark run.
Cauchy.log_probandStudentT.log_probsquare the standardized value insidelog1p. In float32 the square overflows once|z|passes about 1.8e19, so the log density becomes-infand its gradient 0, although the true values are small finite numbers:HalfCauchyand the truncated Cauchy variants go throughCauchy.log_prob, so they have the same problem. With x64 it starts around 1e154.This writes
log(1 + z**2)as2 * log(hypot(1, z)), which is the same quantity without the intermediate square. After the change both lines above print the scipy values, and the gradient at 1e20 is-4e-20for the StudentT example instead of 0. For ordinary values the result differs from the old expression only at rounding level (max 9.5e-7 over 200k Cauchy draws in float32).pytest test/test_distributions.py -k "Cauchy or StudentT"gives 872 passed in float32. WithJAX_ENABLE_X64=1it gives 870 passed and 2 failed,test_left_truncated_cdf[0.0-StudentT-base_params5]andtest_right_truncated_cdf[0.0-StudentT-base_params5], and the same two fail on master without this change.ruffandtyare clean. I left out a regression test, following the reviews on #2331 and #2332, but can add one if wanted.#2328 fixed the Cauchy
cdf/icdftails, notlog_prob. I didn't find another issue or PR for this (searched "Cauchy log_prob", "StudentT log_prob overflow", "HalfCauchy log_prob").AI assistance: I used Claude Code to find this, with the same scipy comparison sweep as #2332, and to draft the change. I checked the numbers above and ran the tests myself.