scipy.optimize.minimize не останавливается на максимуме или обратном вызове - PullRequest
1 голос
/ 22 мая 2019

Я реализовал scipy.optimize.minimize, чтобы минимизировать среднее значение дельта-значений фрейма данных pandas для одномерного массива со 128 значениями.

Кажется, что он запускается и работает, но не останавливаетсяв максимуме iter или в функции обратного вызова, взятой из другого вопроса stackoverflow здесь.

Мой код:

import numpy as np
from scipy.optimize import minimize, rosen
import time
import warnings

class TookTooLong(Warning):
    pass

class MinimizeStopper(object):
    def __init__(self, max_sec=60*60*5):
        self.max_sec = max_sec
        self.start = time.time()
    def __call__(self, xk=None):
        elapsed = time.time() - self.start
        if elapsed > self.max_sec:
            warnings.warn("Terminating optimization: time limit reached",
                          TookTooLong)
        else:
            # you might want to report other stuff here
            print("Elapsed: %.3f sec" % elapsed)

import scipy.optimize
res = scipy.optimize.minimize(minFunct,oned,options= 
            {"disp":True,"maxiter":100},tol=0.01,
                     method ="BFGS",callback=MinimizeStopper(1E-3))

Отображаемое сообщение через некоторое время говорит мне, что maxiter был достигнут и меньшая функциязначение, чем в начале было достигнуто, но это не останавливается.Так как он работает в jupyter, у меня нет возможности достичь res без окончания ячейки.

1 Ответ

1 голос
/ 22 мая 2019

Согласно обратному вызову docs должен вызываться вызов, возвращающий True для завершения и имеющий следующий формат callback(xk).Принимая во внимание, что в вашем коде вы определяете его как инициализацию вашего класса.Вместо этого вы должны определить экземпляр вашего класса, а затем присвоить его __call__() функцию callback следующим образом:

import time
import warnings
import numpy as np
from scipy.optimize import minimize, rosen

class TookTooLong(Warning):
    pass

class MinimizeStopper(object):
    def __init__(self, max_sec=10):
        self.max_sec = max_sec
        self.start   = time.time()

    def __call__(self, xk):
        # callback to terminate if max_sec exceeded
        elapsed = time.time() - self.start
        if elapsed > self.max_sec:
            warnings.warn("Terminating optimization: time limit reached",
                          TookTooLong)
        else:
            # you might want to report other stuff here
            print("Elapsed: %.3f sec" % elapsed)
# init stopper
minimize_stopper = MinimizeStopper()
# minimze
res = minimize(rosen,
               x0       = np.random.randint(5, size=128),
               method   ="BFGS",
               tol      = 0.01,
               options  = {"maxiter":10, "disp":True},
               callback = minimize_stopper.__call__)

В качестве альтернативы вы можете определить класс для вашего минимизатора и построить в нем функцию обратного вызова.прекратить минимизацию через определенное время.Это можно сделать следующим образом:

import time
import warnings
import numpy as np
from scipy.optimize import minimize, rosen


class TookTooLong(Warning):
    pass

class Minimizer:
    def __init__(self, timeout, maxiter):
        self.timeout = timeout
        self.maxiter = maxiter

    def minimize(self):
        self.start_time = time.time()
        # minimize
        res = minimize(rosen,
                       x0       = np.random.randint(5, size=128),
                       method   ="BFGS",
                       tol      = 0.01,
                       options  = {"maxiter":self.maxiter, "disp":True},
                       callback = self.callback)
        return res

    def callback(self, x):
        # callback to terminate if max_sec exceeded
        elapsed = time.time() - self.start_time
        if elapsed > self.timeout:
            warnings.warn("Terminating optimization: time limit reached",
                          TookTooLong)
            return True
        else: 
            print("Elapsed: %.3f sec" % elapsed)

# init minimizer and minimize
minimizer = Minimizer(0.1, 100)
result    = minimizer.minimize()

Проверьте этот код с помощью: timeout=0.1 & maxiter=100 затем timeout=10 & maxiter=10, чтобы наблюдать оба типа завершения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...