¿Cómo mostrar el progreso de la función scipy.optimize?

Uso scipy.optimize para minimizar una función de 12 argumentos.

Comencé la optimización hace un tiempo y todavía estoy esperando resultados.

¿Hay alguna forma de forzar a scipy.optimize para que muestre su progreso (como cuánto se ha hecho, cuáles son los mejores puntos actuales)?

Como sugirió mg007, algunas de las rutinas scipy.optimize permiten una función de callback (desafortunadamente, lesssq no lo permite en este momento). A continuación se muestra un ejemplo que utiliza la rutina “fmin_bfgs” en la que utilizo una función de callback para mostrar el valor actual de los argumentos y el valor de la función objective en cada iteración.

 import numpy as np from scipy.optimize import fmin_bfgs Nfeval = 1 def 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)**2 def 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 += 1 print '{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) 

La salida se ve así:

 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.000000 Optimization terminated successfully. Current function value: 0.000000 Iterations: 11 Function evaluations: 85 Gradient evaluations: 17 

Al menos de esta manera, puedes ver cómo el optimizador rastrea el mínimo

Siguiendo el ejemplo de @ joel, hay una manera limpia y eficiente de hacer lo mismo. El siguiente ejemplo muestra cómo podemos eliminar global variables global , call_back funciones de call_back y la reevaluación de la función de destino varias veces .

 import numpy as np from scipy.optimize import fmin_bfgs def 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 res print '{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, ) 

Esto generará una salida como

 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.000000 Warning: Desired error not necessarily achieved due to precision loss. Current function value: 0.000000 Iterations: 12 Function evaluations: 502 Gradient evaluations: 98 

Sin embargo, no es un lanzamiento gratuito, aquí utilicé function evaluation times lugar de los function evaluation times de algorithmic iteration times como contador. Algunos algoritmos pueden evaluar la función de destino varias veces en una sola iteración.

¿Qué función de minimización está utilizando exactamente?

La mayoría de las funciones tienen un informe de progreso creado, incluidos varios niveles de informes que muestran exactamente los datos que desea, mediante el uso del indicador de disp (por ejemplo, consulte scipy.optimize.fmin_l_bfgs_b ).

Trate de usar:

 options={'disp': True} 

para forzar scipy.optimize.minimize para imprimir resultados intermedios.

A continuación hay una solución que funciona para mí:

 def f_(x): # The rosenbrock function return (1 - x[0])**2 + 100 * (x[1] - x[0]**2)**2 def conjugate_gradient(x0, f): all_x_i = [x0[0]] all_y_i = [x0[1]] all_f_i = [f(x0)] def store(X): x, y = X all_x_i.append(x) all_y_i.append(y) all_f_i.append(f(X)) optimize.minimize(f, x0, method="CG", callback=store, options={"gtol": 1e-12}) return all_x_i, all_y_i, all_f_i 

y por ejemplo:

 conjugate_gradient([2, -1], f_) 

Fuente