Search code examples
pythonoptimizationlmfit

How do minimize() and residual() functions work together in lmfit


I am trying to implement structure from motion in Python and can't really understand how this minimize function works exactly with my residual function. If I pass an array of arguments for representing camera positions and positions of observed points, how will they be treated by my residual function? Will they be fed in row by row (which would be the logic)? But when I print the input from within my residual function I see that all the rows are there. I also use external functions in my residual function that do quaternion decomposition and they don't seem to be happy with lmfit presenting the array of arguments all at once.


Solution

  • I'm not sure I understand how you framed your question, but, you are wondering how the minimize() method works? Also, I am assuming by residual function you are referring to the "objective" function which returns a flattened array of residuals.

    The objective function can be thought of as any other function that you are trying to fit to data, with the difference being that you don't have to specify, explicitly, the ordering of parameters when calling the function (they are embedded in a parameter class) and can use multiple minimization algorithms (levenberg marquardt, simulated annealing, etc.). It can therefore be used for global (shared parameter) fitting (with multiple data sets) with ease through the parameter class. All of these function evaluations return residuals (model - data) which are combined and output as a single residual array.

    So for you, if your parameters are "camera positions" to be used in quaternion functions, these would be optimized to yield the best fit of a model to data minimizing (model - data). You are allowed to use whatever external functions you want within the objective function, just so long as the output from that function is a flattened residual array - lmfit takes care of the rest.

    The only things you have to do are: 1) identify parameters to fit and include them in a parameter class 2) code an objective function (using any external functions you want) that returns a residual array.

    Here is an example:

    If this is a simple model to be evaluated:

    #in this example x,y are the data that are collected, and model contains a function that uses x in fitting to obtain a model y-value.
    
    #create model to evaluate and fit to data
    def model(params, x):
    
        dGA = params['dGA'].value
        dGB = params['dGB'].value
        dGS = params['dGS'].value
    
        return (((dGA*x) + dGb)*dGS) 
    
    #create parameter class
    params = lmfit.Parameters()
    params.add('dGA', value = 2.9)
    params.add('dGB', value = 2.89)
    params.add('dGS', value = 3.6)
    
    #now setup objective function which uses the model function
    def objective(params):
    
        finalresid = []
    
        dGA = params['dGA'].value
        dGB = params['dGB'].value
        dGS = params['dGS'].value
    
        #can setup loop or anything for multiple data sets (y below)
        #if multiple, just have to lump all residuals into a 
        #single flattened array. You could do this by setting up a loop over
        #all data sets, and combine the residuals at the end
    
        resid = (y - model(params, x))
    
    return resid.flatten() 
    
    #now call mimimize() over the objective function with respect to the parameters
    result = lmfit.minimize(objective, params)
    

    All relevant information can be obtained from results (check the docs).

    Hope this helps, but I cannot comment to ask questions about what you are asking.