Skip to content

perf(hierarchical): faster options for EmpiricalBayes and VariationalBayes - #103

Merged
lenarddome merged 10 commits into
mainfrom
experimental/hierarchical
Oct 14, 2026
Merged

lenarddome merged 10 commits into
mainfrom
experimental/hierarchical

Conversation

@lenarddome

Copy link
Copy Markdown
Collaborator

Speeds up hierarchical fitting. The defaults are unchanged, so results for a fixed seed stay the same; the faster paths are options.

In a speed comparison with cbm (RLRW, 100 participants, 120 trials), cpm made about as many objective evaluations as cbm but each one cost more: 17.3 against 5.0 ms per participant and iteration. These changes reduce that cost.

Changes

  • FminBound with approx_grad=True computes the finite-difference gradient itself, together with the objective, as SciPy does. The results are bit-identical, and hierarchical fits are 19% faster.
  • New hessian argument on FminBound, Fmin, Minimize and Bads. hessian="finite_differences" computes the Hessian at the optimum with bounded finite differences, using 7 instead of 22 evaluations per participant and iteration. The default, "numdifftools", keeps the previous Hessian.
  • New start argument on EmpiricalBayes and VariationalBayes. start="prior_mean" starts every participant's first optimisation from the current prior's location, clipped into the bounds, as cbm does. The default, "random", keeps the previous starts.
  • New positive_definite column in the fit of EmpiricalBayes and VariationalBayes, and a not_positive_definite count in their hyperparameters. Estimates on a bound can have a Hessian that is not positive definite; they are kept because the bounds must be respected.
  • benchmarks/hierarchical_profile.py profiles a VariationalBayes fit. The before/after results and the cbm comparison are in benchmarks/results/.
  • LogLikelihood.bernoulli skips nan_to_num when every value is finite.
  • Version bumped to 0.26.0.dev3, with a changelog entry.

Results

Using hessian="finite_differences", start="prior_mean" and number_of_starts=1 together brings EmpiricalBayes from 20.8 to 6.8 ms per participant and iteration, and VariationalBayes from 20.1 to 7.0 ms. cbm takes 4.4 ms. Throughout, RMSE against 0.26.0.dev1 stays within the bootstrap 95% intervals.

Testing

  • New tests cover the gradient (identical to SciPy), the finite-difference Hessian (including near the bounds), the hessian option on every optimiser, start, and the positive-definite record.
  • The full suite passes locally on Windows after merging main: 755 tests. I didn't build the docs locally.

Not addressed here

  • FminBound(parallel=True) finds worse optima than serial runs.
  • With 3 or more starts, FminBound compares later starts only with the first.
  • The VariationalBayes docstring gives 1000 as the default for iteration; the code uses 50.

🤖 Generated with Claude Code

lenarddome and others added 10 commits October 6, 2026 10:32
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@lenarddome
lenarddome merged commit e554018 into main Oct 14, 2026
16 checks passed
@lenarddome
lenarddome deleted the experimental/hierarchical branch October 14, 2026 11:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant