How to display progress of scipy.optimize function? How to display progress of scipy.optimize function? python python

How to display progress of scipy.optimize function?


As mg007 suggested, some of the scipy.optimize routines allow for a callback function (unfortunately leastsq does not permit this at the moment). Below is an example using the "fmin_bfgs" routine where I use a callback function to display the current value of the arguments and the value of the objective function at each iteration.

import numpy as npfrom scipy.optimize import fmin_bfgsNfeval = 1def rosen(X): #Rosenbrock function    return (1.0 - X[0])**2 + 100.0 * (X[1] - X[0]**2)**2 + \           (1.0 - X[1])**2 + 100.0 * (X[2] - X[1]**2)**2def callbackF(Xi):    global Nfeval    print '{0:4d}   {1: 3.6f}   {2: 3.6f}   {3: 3.6f}   {4: 3.6f}'.format(Nfeval, Xi[0], Xi[1], Xi[2], rosen(Xi))    Nfeval += 1print  '{0:4s}   {1:9s}   {2:9s}   {3:9s}   {4:9s}'.format('Iter', ' X1', ' X2', ' X3', 'f(X)')   x0 = np.array([1.1, 1.1, 1.1], dtype=np.double)[xopt, fopt, gopt, Bopt, func_calls, grad_calls, warnflg] = \    fmin_bfgs(rosen,               x0,               callback=callbackF,               maxiter=2000,               full_output=True,               retall=False)

The output looks like this:

Iter    X1          X2          X3         f(X)         1    1.031582    1.062553    1.130971    0.005550   2    1.031100    1.063194    1.130732    0.004973   3    1.027805    1.055917    1.114717    0.003927   4    1.020343    1.040319    1.081299    0.002193   5    1.005098    1.009236    1.016252    0.000739   6    1.004867    1.009274    1.017836    0.000197   7    1.001201    1.002372    1.004708    0.000007   8    1.000124    1.000249    1.000483    0.000000   9    0.999999    0.999999    0.999998    0.000000  10    0.999997    0.999995    0.999989    0.000000  11    0.999997    0.999995    0.999989    0.000000Optimization terminated successfully.         Current function value: 0.000000         Iterations: 11         Function evaluations: 85         Gradient evaluations: 17

At least this way you can watch as the optimizer tracks the minimum


Following @joel's example, there is a neat and efficient way to do the similar thing. Following example show how can we get rid of global variables, call_back functions and re-evaluating target function multiple times.

import numpy as npfrom scipy.optimize import fmin_bfgsdef rosen(X, info): #Rosenbrock function    res = (1.0 - X[0])**2 + 100.0 * (X[1] - X[0]**2)**2 + \           (1.0 - X[1])**2 + 100.0 * (X[2] - X[1]**2)**2    # display information    if info['Nfeval']%100 == 0:        print '{0:4d}   {1: 3.6f}   {2: 3.6f}   {3: 3.6f}   {4: 3.6f}'.format(info['Nfeval'], X[0], X[1], X[2], res)    info['Nfeval'] += 1    return resprint  '{0:4s}   {1:9s}   {2:9s}   {3:9s}   {4:9s}'.format('Iter', ' X1', ' X2', ' X3', 'f(X)')   x0 = np.array([1.1, 1.1, 1.1], dtype=np.double)[xopt, fopt, gopt, Bopt, func_calls, grad_calls, warnflg] = \    fmin_bfgs(rosen,               x0,               args=({'Nfeval':0},),               maxiter=1000,               full_output=True,               retall=False,              )

This will generate output like

Iter    X1          X2          X3         f(X)        0    1.100000    1.100000    1.100000    2.440000 100    1.000000    0.999999    0.999998    0.000000 200    1.000000    0.999999    0.999998    0.000000 300    1.000000    0.999999    0.999998    0.000000 400    1.000000    0.999999    0.999998    0.000000 500    1.000000    0.999999    0.999998    0.000000Warning: Desired error not necessarily achieved due to precision loss.         Current function value: 0.000000         Iterations: 12         Function evaluations: 502         Gradient evaluations: 98

However, no free launch, here I used function evaluation times instead of algorithmic iteration times as a counter. Some algorithms may evaluate target function multiple times in a single iteration.


Try using:

options={'disp': True} 

to force scipy.optimize.minimize to print intermediate results.