Replies: 4 comments 5 replies
-
@bertinets What haapens if the "definition" is more complex than a single line? Even a little more complex (say, RectangleModel) would be very hard to render or use for automated differentiation. The function definitions are expected to be in Python, not parseable mathematical strings. It should also be mentioned that trying to use |
Beta Was this translation helpful? Give feedback.
-
@bertinets But, how would you know that you need to use "Piecewise"? What if the definition includes a function that sympy does not recognize or identifies incorrectly? Like, what would your plan be for "Voigt", defined as "amplitudewofz(z).real / (sigmas2pi)", or "Pearson4" or "Pearson7" which use other functions from scipy but not provided in numpy? What if the function is more than a one-line expression? Perhaps if you show that using a sympy-generated analytic Jacobian can work, and is faster for a very simple like Gaussian (including the bound sigma > 0), then we can worry about how to make that more easily generalizable. |
Beta Was this translation helpful? Give feedback.
-
@newville
The optimisation problem is solved correctly and running With an exact (analytical) jacobian things change dramatically:
Now In this case (of course this cannot be generalised to all of the cases) there is more than a 100 fold speed increase in running the optimisation with the exact jacobian. Note that this exact jacobian can also be used to calculate exactly (rather than estimate with a numerical evaluation) the covariance matrix for the estimation of the errors on the fitting parameters. Going back to the other 2 points:
Anyway, I actually raised the initial point mostly because I think it would be useful for a user to have access to the mathematical definition used to build the model function with a simple call to a method or an attribute of the class. I am happy to provide the strings-like expression if you think it would be a good idea to have this implemented (I already have them for 80% of the lmfit models). Of course if the string would be parsable by sympy it would be a plus for me (not sure how many other users would use the string the way I would). |
Beta Was this translation helpful? Give feedback.
-
@bertinets I am somewhat sympathetic to the idea of trying to add analytic derivatives. Of course, it can help improve performance. Improving raw performance is good, but it is not the only consideration. And, for sure, adding analytic derivatives to lmfit is not going to be easy - they would need to manage parameter bounds and fixed parameters. I am also definitely sympathetic to people trying to fit large amounts of X-ray data, say from synchrotrons. But: if the claim is that something is taking 1000 function evaluations, you should back that up. It is completely believable to me that your rather convoluted code is not doing exactly what you think it is. A simplified use of your code would be: import numpy as np
from lmfit.models import StepModel, LinearModel
xv = np.linspace(0, 10, 45)
yv = np.ones_like(xv)
yv[:12] = 0.0
yv[12:15] = np.arange(15-12)/(15.0-12)
np.random.seed(0)
yv = 110.2 * (yv + 9e-2*np.random.randn(xv.size)) + 12.0 + 2.22*xv
model = StepModel(form='logistic', prefix='step_') + LinearModel(prefix='line_')
params = model.make_params(step_center=2.5, step_amplitude=100, step_sigma=0.5,
line_slope=1, line_intercept=20)
params['step_sigma'].min = 0
result = model.fit(yv, params, x=xv)
print(result.fit_report())
print('fit took %.4f sec' % (time.time()-t0)) which gives a good fit, and prints a report of
A good fit is found with 79 function evaluations, in under 10 msec. With a script that could be read and understood by any undergraduate. I do not know how you managed to get 1000 function evaluations. It's OK to say that things could be optimized. It is important to be clear-eyed about the facts, and decide what is to be optimized. If you need fits to go 10x faster, consider using 10 cores to do 10 fits at once, right? |
Beta Was this translation helpful? Give feedback.
-
I think it would be useful to have a string representation of the mathematical definition of the model, especially for the built-in models, so that one could quickly check what is the functional form of the expression used to generate the model.
For example:
would return the string:
'amplitude* e^(-x/decay)'
or
would return the string:
'1/(amplitude*exp((x - center)/(kt)))'
Also, I am bringing this up because I am using lmfit in combination with sympy, which I use to calculate the analytic jacobian of the fitting model that in turn can be used to speed up least_squares. For this sake, at the moment, I have taken from the lmfit documentation of the line shapes definition the expressions of all the models and transformed them in a string that can be used to generate a symbolic function using sympy.sympify.
It would be of course easier if one could do that in a single step like for example:
Or maybe this is already possible with the current version of lmfit? I have read the documentation and the code quite extensively and I couldn't find a way to generate the model's mathematical expression as a string.
Beta Was this translation helpful? Give feedback.
All reactions