2013-05-24 1 views
23

Я использую scipy.optimize для минимизации функции из 12 аргументов.Как показать ход функции scipy.optimize?

Я начал оптимизацию некоторое время назад и все еще жду результатов.

Есть ли способ заставить scipy.optimize показать свой прогресс (например, сколько уже сделано, какова текущая лучшая точка)?

+4

Вы проверили параметр 'callback' вашей функции минимизации? – mg007

+0

Для другого подхода без «обратного вызова» см. [Funcgradmon] (http://stackoverflow.com/questions/40002172/resuming-an-optimization-in-scipy-optimize/40059852#40059852). Он сохраняет все значения 'x f g', а затем записывает их в файл для построения. – denis

ответ

22

Как предположил mg007, некоторые из подпрограмм scipy.optimize позволяют выполнять функцию обратного вызова (к сожалению, lesssq на данный момент этого не разрешает). Ниже приведен пример, использующий процедуру «fmin_bfgs», где я использую функцию обратного вызова для отображения текущего значения аргументов и значения целевой функции на каждой итерации.

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) 

Результат выглядит следующим образом:

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 

По крайней мере, таким образом, вы можете наблюдать, как оптимизатор отслеживает минимальную функцию

+6

это похоже супер неэффективный. вам нужно снова вызвать функцию оптимизации в обратном вызове? добавляет ли обратный вызов таким образом, чтобы оптимизация прошла вдвое медленнее? – dbliss

3

Какие минимизации вы используете именно?

У большинства функций есть отчет о ходе выполнения, включая несколько уровней отчетов, показывающих точно нужные вам данные, с использованием флага disp (например, см. scipy.optimize.fmin_l_bfgs_b).

3

Следуя примеру @ joel, существует аккуратный и эффективный способ сделать аналогичную вещь. В следующем примере показано, как мы можем избавиться от переменных global, call_back и повторной оценки целевой функции несколько раз.

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, 
      ) 

Это будет генерировать выходной сигнал, как

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 

Однако нет свободного запуска, здесь я использовал function evaluation times вместо algorithmic iteration times в качестве счетчика. Некоторые алгоритмы могут оценивать целевую функцию несколько раз за одну итерацию.

2

Попробуйте использовать:

options={'disp': True} 

заставить scipy.optimize.minimize печатать промежуточные результаты.

+0

Документация предполагает, что это правильный ответ, но на практике это не работает для меня. –