Skip to content
JD Smith edited this page Apr 6, 2022 · 1 revision

Improving speed:

Python PAHFIT is somewhat slow, a bit slower (on my machine) than IDL PAHFIT was. Once typical spectra have 5-10x as many wavlelength samples, and the model is expanded to have 3-5x as many parameters, this will really start to hurt. More than several minute fit times on decent hardware are quite likely. Once the model has settled a bit more, striving for performance gains will be important.

Python vs. IDL. PAHFIT

Example: M101_Nucleus_irs.ipac (from /data/)

IDL PAHFIT

With default settings (xtol=ftol=gtol=1D-10), the fit converges in:

  • 71 “iterations”, using 6754 function evals
  • 3.9 seconds
  • 1732 FEVs/second

Python PAHFIT

With the default acc=eps=1D-10, the fit converges in:

  • 6.6s
  • 814 function evaluations
  • 123 FEVs/second

So Python PAHFIT (including overhead) is about 14x slower per model function call, but makes up some of this by converging in fewer calls.

Python PAHFIT with Akari+Spitzer

Fitting the Akari + Spitzer SL/LL template spectrum is quite slow at present (v2.1)…

  • 58.7s
  • 4566 FEVs
  • 77.8 FeVs/sec (oy!)

Much slower with the new science pack. A profiler report indicates much of this time in spent

Python PAHFIT with ISO-SWS

Anecdotal evidence is that these spectra take minutes to hours to converge.

Freeze line widths

Allowing all lines and features to vary in position and width is very expensive. And hopefully (for unresolved lines), unnecessary.

A good instrument and science pack model should nail the position and widths of lines precisely. Any mismatch in the residuals should be considered an “opportunity to improve” either the rest line wavelength in the sci-pack, or the fwhm estimation at each wavelength in the instrument pack. There is some concern about NIRSPEC wavelength calibration repeatability, but this should be corrected prior to PAHFIT’ing.

Apply bounding boxes to constrain lines/features to local “region of influence”

astropy.modeling includes bounds of significance or bounding boxes. The classic case is a 2D star PSF on a large image; evaluating one stars PSF across the entire image is needlessly wasteful. Some savings may occur for lines and features.

5 * max(fwhm) should do it (or 3x for Gaussians, 5x for Drudes; can investigate).

Profile

Should profile slow fits to see where the time is being spent. Mostly in the model function(s)?

Investigate machine-compiled model-functions

Numba is a nice and very easy-to-use decorator-based framework for transpiling to C, with numpy support. It is not compatible with scipy functions (which themselves call to compiled C/FORTRAN code). But the bottommost objective function apparently can be @jit’d: Example of optimize.leastsq with Numba.

To use numba we would probably need to re-write the model as a set of simple functions call from the objective function, and give up on CompoundModel.

Analytical derivatives

The fit_deriv callable for fittable models can be used to speed up derivative estimation.

This would mean giving up on the conveniences of the CompoundModel, which in practice might mean just switching to scipy.least_squares (newer than the scipy.leastsq that LevMarLSQFitter uses internally). It natively supports bounds.

A very common source of optimization not converging well is human error in the computation of the gradient. You can use scipy.optimize.check_grad() to check that your gradient is correct. It returns the norm of the different between the gradient given, and a gradient computed numerically.

Some consider analytic derivatives not worth the overhead. Probably this would be a last resort.