Sibbs Gambling
Sibbs Gambling

Reputation: 20355

Inspect internal variables as scipy.optimize.minimize runs?

I usually inspect my variables with pdb as my program runs. Now I wish to debug my scipy.optimize.minimize by inspecting the variables as the optimization runs.

result = scipy.optimize.minimize(fun, x0, method='dogleg')

I tried using the callback option, but it doesn't give me access to the optimization's internal parameters, such as the Jacobian matrix, etc.

The returned result does have all the information I need, but it's only returned at the end of the entire optimization, but I need the (intermediate) results as the optimization runs.

So my question: how do I return the intermediate optimization parameters (such as Jacobian) as scipy.optimize.minimize runs?

Upvotes: 4

Views: 1033

Answers (1)

wim
wim

Reputation: 362826

The easy way:

Just edit your local copy of scipy directly, chucking in printouts or logging into the source files directly. You said this was just for debugging, anyway. You could modify the callback to pass more info along. Or, you could insert the pdb.set_trace() directly there into the optimization code and look around interactively. To find which file you should be hacking around in, locate where the module is:

scipy.optimize.__file__

and then follow the trail. You might want to delete any .pyc files hanging around. In current scipy, it's located here in _minimize_trust_region.

The "clever" way:

You can use introspection to step back a frame and find the local variables, without needing to modify scipy sources directly. Using frame hacks is fragile and implementation dependent, so by all means experiment with it for debugging but don't let stuff like this into any actual library code.

from scipy.optimize import minimize
import inspect

def fun(x):
    return (x - 42)**2

def jac(x):
    return 2*(x - 42)

def hess(x):
    return [[2]]

def vanilla_cb(x):
    print(x)

def callback_on_crack(x):
    print(inspect.currentframe().f_back.f_locals)
    print(x)

Using the plain callback, and starting at x0=99 we reach the minimum 42 after 6 iterations:

>>> minimize(fun,x0=99,method='dogleg',jac=jac,hess=hess,callback=vanilla_cb)
[ 98.]
[ 96.]
[ 92.]
[ 84.]
[ 68.]
[ 42.]

Using the souped-up callback, you can see all the good stuff in a dict!

>>> minimize(fun,99,method='dogleg',jac=jac,hess=hess,callback=callback_on_crack)
{'disp': False, 'unknown_options': {}, 'm': <scipy.optimize._trustregion_dogleg.DoglegSubproblem object at 0xdc9d10>, 'm_proposed': <scipy.optimize._trustregion_dogleg.DoglegSubproblem object at 0xdc9d10>, 'return_all': False, 'hess': <function function_wrapper at 0x1248938>, 'callback': <function callback_on_crack at 0x12487d0>, 'nhessp': [0], 'njac': [1], 'predicted_reduction': array([ 113.]), 'subproblem': <class 'scipy.optimize._trustregion_dogleg.DoglegSubproblem'>, 'maxiter': 200, 'warnflag': 0, 'gtol': 0.0001, 'args': (), 'initial_trust_radius': 1.0, 'hits_boundary': True, 'trust_radius': 2.0, 'predicted_value': array([ 3136.]), 'rho': array([ 1.]), 'x': array([ 98.]), 'nhess': [1], 'x0': array([ 99.]), 'hessp': None, 'k': 0, 'actual_reduction': array([ 113.]), 'jac': <function function_wrapper at 0x12488c0>, 'p': array([-1.]), 'eta': 0.15, 'fun': <function function_wrapper at 0x1248848>, 'nfun': [2], 'max_trust_radius': 1000.0, 'x_proposed': array([ 98.])}
[ 98.]
{'disp': False, 'unknown_options': {}, 'm': <scipy.optimize._trustregion_dogleg.DoglegSubproblem object at 0xdc9d90>, 'm_proposed': <scipy.optimize._trustregion_dogleg.DoglegSubproblem object at 0xdc9d90>, 'return_all': False, 'hess': <function function_wrapper at 0x1248938>, 'callback': <function callback_on_crack at 0x12487d0>, 'nhessp': [0], 'njac': [2], 'predicted_reduction': array([ 220.]), 'subproblem': <class 'scipy.optimize._trustregion_dogleg.DoglegSubproblem'>, 'maxiter': 200, 'warnflag': 0, 'gtol': 0.0001, 'args': (), 'initial_trust_radius': 1.0, 'hits_boundary': True, 'trust_radius': 4.0, 'predicted_value': array([ 2916.]), 'rho': array([ 1.]), 'x': array([ 96.]), 'nhess': [2], 'x0': array([ 99.]), 'hessp': None, 'k': 1, 'actual_reduction': array([ 220.]), 'jac': <function function_wrapper at 0x12488c0>, 'p': array([-2.]), 'eta': 0.15, 'fun': <function function_wrapper at 0x1248848>, 'nfun': [3], 'max_trust_radius': 1000.0, 'x_proposed': array([ 96.])}
[ 96.]
{'disp': False, 'unknown_options': {}, 'm': <scipy.optimize._trustregion_dogleg.DoglegSubproblem object at 0xdc9e50>, 'm_proposed': <scipy.optimize._trustregion_dogleg.DoglegSubproblem object at 0xdc9e50>, 'return_all': False, 'hess': <function function_wrapper at 0x1248938>, 'callback': <function callback_on_crack at 0x12487d0>, 'nhessp': [0], 'njac': [3], 'predicted_reduction': array([ 416.]), 'subproblem': <class 'scipy.optimize._trustregion_dogleg.DoglegSubproblem'>, 'maxiter': 200, 'warnflag': 0, 'gtol': 0.0001, 'args': (), 'initial_trust_radius': 1.0, 'hits_boundary': True, 'trust_radius': 8.0, 'predicted_value': array([ 2500.]), 'rho': array([ 1.]), 'x': array([ 92.]), 'nhess': [3], 'x0': array([ 99.]), 'hessp': None, 'k': 2, 'actual_reduction': array([ 416.]), 'jac': <function function_wrapper at 0x12488c0>, 'p': array([-4.]), 'eta': 0.15, 'fun': <function function_wrapper at 0x1248848>, 'nfun': [4], 'max_trust_radius': 1000.0, 'x_proposed': array([ 92.])}
[ 92.]
{'disp': False, 'unknown_options': {}, 'm': <scipy.optimize._trustregion_dogleg.DoglegSubproblem object at 0xdc9dd0>, 'm_proposed': <scipy.optimize._trustregion_dogleg.DoglegSubproblem object at 0xdc9dd0>, 'return_all': False, 'hess': <function function_wrapper at 0x1248938>, 'callback': <function callback_on_crack at 0x12487d0>, 'nhessp': [0], 'njac': [4], 'predicted_reduction': array([ 736.]), 'subproblem': <class 'scipy.optimize._trustregion_dogleg.DoglegSubproblem'>, 'maxiter': 200, 'warnflag': 0, 'gtol': 0.0001, 'args': (), 'initial_trust_radius': 1.0, 'hits_boundary': True, 'trust_radius': 16.0, 'predicted_value': array([ 1764.]), 'rho': array([ 1.]), 'x': array([ 84.]), 'nhess': [4], 'x0': array([ 99.]), 'hessp': None, 'k': 3, 'actual_reduction': array([ 736.]), 'jac': <function function_wrapper at 0x12488c0>, 'p': array([-8.]), 'eta': 0.15, 'fun': <function function_wrapper at 0x1248848>, 'nfun': [5], 'max_trust_radius': 1000.0, 'x_proposed': array([ 84.])}
[ 84.]
{'disp': False, 'unknown_options': {}, 'm': <scipy.optimize._trustregion_dogleg.DoglegSubproblem object at 0xdc9e10>, 'm_proposed': <scipy.optimize._trustregion_dogleg.DoglegSubproblem object at 0xdc9e10>, 'return_all': False, 'hess': <function function_wrapper at 0x1248938>, 'callback': <function callback_on_crack at 0x12487d0>, 'nhessp': [0], 'njac': [5], 'predicted_reduction': array([ 1088.]), 'subproblem': <class 'scipy.optimize._trustregion_dogleg.DoglegSubproblem'>, 'maxiter': 200, 'warnflag': 0, 'gtol': 0.0001, 'args': (), 'initial_trust_radius': 1.0, 'hits_boundary': True, 'trust_radius': 32.0, 'predicted_value': array([ 676.]), 'rho': array([ 1.]), 'x': array([ 68.]), 'nhess': [5], 'x0': array([ 99.]), 'hessp': None, 'k': 4, 'actual_reduction': array([ 1088.]), 'jac': <function function_wrapper at 0x12488c0>, 'p': array([-16.]), 'eta': 0.15, 'fun': <function function_wrapper at 0x1248848>, 'nfun': [6], 'max_trust_radius': 1000.0, 'x_proposed': array([ 68.])}
[ 68.]
{'disp': False, 'unknown_options': {}, 'm': <scipy.optimize._trustregion_dogleg.DoglegSubproblem object at 0xdc9d50>, 'm_proposed': <scipy.optimize._trustregion_dogleg.DoglegSubproblem object at 0xdc9d50>, 'return_all': False, 'hess': <function function_wrapper at 0x1248938>, 'callback': <function callback_on_crack at 0x12487d0>, 'nhessp': [0], 'njac': [6], 'predicted_reduction': array([ 676.]), 'subproblem': <class 'scipy.optimize._trustregion_dogleg.DoglegSubproblem'>, 'maxiter': 200, 'warnflag': 0, 'gtol': 0.0001, 'args': (), 'initial_trust_radius': 1.0, 'hits_boundary': False, 'trust_radius': 32.0, 'predicted_value': array([ 0.]), 'rho': array([ 1.]), 'x': array([ 42.]), 'nhess': [6], 'x0': array([ 99.]), 'hessp': None, 'k': 5, 'actual_reduction': array([ 676.]), 'jac': <function function_wrapper at 0x12488c0>, 'p': array([-26.]), 'eta': 0.15, 'fun': <function function_wrapper at 0x1248848>, 'nfun': [7], 'max_trust_radius': 1000.0, 'x_proposed': array([ 42.])}
[ 42.]

Upvotes: 2

Related Questions