Skip to content

Improve fitting performance of most non-linear fitters#16673

Merged
nden merged 4 commits intoastropy:mainfrom
astrofrog:improve-modeling-performance
Aug 10, 2024
Merged

Improve fitting performance of most non-linear fitters#16673
nden merged 4 commits intoastropy:mainfrom
astrofrog:improve-modeling-performance

Conversation

@Cadair
Copy link
Member

@Cadair Cadair commented Jul 4, 2024

This PR significantly speeds up fitting of models for most of the non-linear fitters. When profiling this, we found that a lot of the overhead was in the fact that the fitters evaluate the model using call, which includes several time-consuming pre- and post-evaluation steps. However, in the non-linear fitters, the models always have scalar parameters and we have control over the inputs to the models, so these checks are unnecessary. We can therefore call Model.evaluate directly which speeds things up a lot. For compound models, this can speed up the fitting by factors of 4x or more.

For a simple 1D Gaussian unconstrained fit:

Fit example
import time
import numpy as np
from astropy.modeling.models import Gaussian1D
from astropy.modeling.fitting import TRFLSQFitter

g = Gaussian1D()
fitter = TRFLSQFitter()

np.random.seed(12345)

x = np.linspace(-10, 10, 100)
y = np.exp(-(x - 1.1) ** 2 / 3) + np.random.uniform(-0.2, 0.2, 100)

start = time.time()
for iter in range(1000):
    g_fit = fitter(g, x, y)
end = time.time()

print(f"{end-start}")

This takes the run time for me from 3.02s on main to 2.19s on this PR.

With use_min_max_constraints and bounds set it goes from 3.64s to 2.2s.

If you change the model being fit to g = Gaussian1D() + Gaussian1D() then it takes 27.9s on main and 9.4s on this PR.

  • By checking this box, the PR author has requested that maintainers do NOT use the "Squash and Merge" button. Maintainers should respect this when possible; however, the final decision is at the discretion of the maintainer that merges the PR.

@Cadair Cadair added modeling Performance benchmark Run benchmarks for a PR labels Jul 4, 2024
@github-actions
Copy link
Contributor

github-actions bot commented Jul 4, 2024

Thank you for your contribution to Astropy! 🌌 This checklist is meant to remind the package maintainers who will review this pull request of some common things to look for.

  • Do the proposed changes actually accomplish desired goals?
  • Do the proposed changes follow the Astropy coding guidelines?
  • Are tests added/updated as required? If so, do they follow the Astropy testing guidelines?
  • Are docs added/updated as required? If so, do they follow the Astropy documentation guidelines?
  • Is rebase and/or squash necessary? If so, please provide the author with appropriate instructions. Also see instructions for rebase and squash.
  • Did the CI pass? If no, are the failures related? If you need to run daily and weekly cron jobs as part of the PR, please apply the "Extra CI" label. Codestyle issues can be fixed by the bot.
  • Is a change log needed? If yes, did the change log check pass? If no, add the "no-changelog-entry-needed" label. If this is a manual backport, use the "skip-changelog-checks" label unless special changelog handling is necessary.
  • Is this a big PR that makes a "What's new?" entry worthwhile and if so, is (1) a "what's new" entry included in this PR and (2) the "whatsnew-needed" label applied?
  • At the time of adding the milestone, if the milestone set requires a backport to release branch(es), apply the appropriate "backport-X.Y.x" label(s) before merge.

@github-actions
Copy link
Contributor

github-actions bot commented Jul 4, 2024

👋 Thank you for your draft pull request! Do you know that you can use [ci skip] or [skip ci] in your commit messages to skip running continuous integration tests until you are ready?

@Cadair Cadair force-pushed the improve-modeling-performance branch 2 times, most recently from f9855e9 to f7cd5ec Compare July 4, 2024 13:39
@Cadair
Copy link
Member Author

Cadair commented Jul 4, 2024

The test fails are due to #16675

@astrofrog
Copy link
Member

I've split out some of the changes here that relate to the Model API into #16677

@pllim pllim added this to the v7.0.0 milestone Jul 5, 2024
@Cadair Cadair force-pushed the improve-modeling-performance branch 2 times, most recently from b98648e to 65c65c7 Compare July 10, 2024 15:43
@Cadair Cadair marked this pull request as ready for review July 10, 2024 15:44
@Cadair Cadair requested a review from a team as a code owner July 10, 2024 15:44
@pllim
Copy link
Member

pllim commented Jul 11, 2024

Please use the new perf change log category, see:

@astrofrog
Copy link
Member

@pllim already done :)

@pllim
Copy link
Member

pllim commented Jul 11, 2024

I think you need to rebase because the bot does not know about "perf" here.

@Cadair Cadair force-pushed the improve-modeling-performance branch from f02719c to 390780d Compare July 11, 2024 15:34
@Cadair
Copy link
Member Author

Cadair commented Jul 11, 2024

My kingdom for that update and rebase button on the github web ui

@astrofrog
Copy link
Member

The asv benchmarks seem to be working! The one regression is a fluke.

@astrofrog
Copy link
Member

astrofrog commented Jul 15, 2024

For convenience:

2024-07-11T16:08:05.5964106Z | Change   | Before [ff59e9cf]    | After [2a05840e]    |   Ratio | Benchmark (Parameter)                                         |
2024-07-11T16:08:05.5966580Z |----------|----------------------|---------------------|---------|---------------------------------------------------------------|
2024-07-11T16:08:05.5968188Z | -        | 103±3ms              | 63.2±0.3ms          |    0.61 | modeling.fitting.time_datafit_compound_LevMarLSQFitter        |
2024-07-11T16:08:05.5972159Z | -        | 2.17±0.03ms          | 968±7μs             |    0.45 | modeling.fitting.time_Gaussian1D_LevMarLSQFitter              |
2024-07-11T16:08:05.5973944Z | -        | 368±60μs             | 162±3μs             |    0.44 | units.time_quantity_array_conversion                          |
2024-07-11T16:08:05.5975459Z | -        | 289±70μs             | 92.4±0.7μs          |    0.32 | units.time_quantity_init_array                                |
2024-07-11T16:08:05.5977071Z | -        | 260±2ms              | 64.9±0.3ms          |    0.25 | modeling.fitting.time_large_gauss_combined_1d_LevMarLSQFitter |
2024-07-11T16:08:05.5978602Z | -        | 19.9±4ms             | 4.22±0.02ms         |    0.21 | modeling.fitting.time_combined_gauss_1d_LevMarLSQFitter       |
2024-07-11T16:08:05.5980178Z | -        | 176±30μs             | 35.8±0.2μs          |    0.2  | units.time_quantity_creation                                  |
2024-07-11T16:08:05.5981557Z | Change   | Before [ff59e9cf]    | After [2a05840e]    |   Ratio | Benchmark (Parameter)          |
2024-07-11T16:08:05.5982920Z |----------|----------------------|---------------------|---------|--------------------------------|
2024-07-11T16:08:05.5984049Z | +        | 41.8±0.1μs           | 83.2±40μs           |    1.99 | units.time_quantity_times_unit |
2024-07-11T16:08:05.5985127Z 
2024-07-11T16:08:05.5985548Z SOME BENCHMARKS HAVE CHANGED SIGNIFICANTLY.

@astrofrog
Copy link
Member

The fitting results are all genuine and reliable (they are on the >1ms level). Not sure what's up with the units results but they are on the microsecond level so maybe just can't measure that in CI?

Copy link
Contributor

@nden nden left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@pllim
Copy link
Member

pllim commented Aug 10, 2024

Does this comment need to be resolved? 👉 #16673 (comment)

@astrofrog
Copy link
Member

astrofrog commented Aug 10, 2024

No I was just commenting that the units asv tests were unreliable but not related to the changes here. This is good to go.

@nden nden merged commit f788114 into astropy:main Aug 10, 2024
@mcara
Copy link
Contributor

mcara commented Sep 9, 2024

This PR is breaking code that relies on documented behavior, specifically: https://docs.astropy.org/en/stable/api/astropy.modeling.fitting.LevMarLSQFitter.html#astropy.modeling.fitting.LevMarLSQFitter.objective_function

It introduces additional parameters to args that are not expected. This is a change in API (maybe not formally but still, changing arguments provided to a callback has similar effects).

@pllim
Copy link
Member

pllim commented Sep 10, 2024

Oh no! We should either

  1. address the API change and document it, or
  2. revert this PR, see Revert "Improve fitting performance of most non-linear fitters" #16979

@astrofrog
Copy link
Member

astrofrog commented Sep 10, 2024

I have an idea to fix this, can take a look this morning unless @Cadair beats me to it.

@neutrinoceros
Copy link
Contributor

Thanks for the heads up @astrofrog ! I was about to give it a try myself, glad we could avoid another race condition :)

@pllim
Copy link
Member

pllim commented Sep 10, 2024

Is #16982 @Cadair beating @astrofrog to it?

@Cadair
Copy link
Member Author

Cadair commented Sep 10, 2024

Yes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants