Как изменить max_iter в функции оптимизации, используемой для регрессии гауссовского процесса sklearn?

Я использую библиотеку георадаров sklearn, но иногда сталкиваюсь с раздражающим предупреждением:

ConvergenceWarning: lbfgs failed to converge (status=2):
ABNORMAL_TERMINATION_IN_LNSRCH.

Increase the number of iterations (max_iter) or scale the data as shown in:
    https://scikit-learn.org/stable/modules/preprocessing.html
  _check_optimize_result("lbfgs", opt_res)

Я не только не могу найти почти никакой документации по этому предупреждению, max_iter вообще не является параметром в модели георадара sklearn. Я попытался изменить масштаб данных, как было предложено, но это не сработало, и, честно говоря, я этого не понял (нужно ли мне также масштабировать вывод? Опять же, небольшая документация).

Увеличение максимального числа итераций в процессе оптимизации имеет смысл, но у sklearn, похоже, нет способа сделать это, что расстраивает, потому что они предлагают это в ответ на это предупреждение.

Взглянув на исходный код GPR, sklearn вызывает оптимизатор:

 def _constrained_optimization(self, obj_func, initial_theta, bounds):
        if self.optimizer == "fmin_l_bfgs_b":
            opt_res = scipy.optimize.minimize(
                obj_func, initial_theta, method="L-BFGS-B", jac=True,
                bounds=bounds)
            _check_optimize_result("lbfgs", opt_res)
            theta_opt, func_min = opt_res.x, opt_res.fun
        elif callable(self.optimizer):
            theta_opt, func_min = \
                self.optimizer(obj_func, initial_theta, bounds=bounds)
        else:
            raise ValueError("Unknown optimizer %s." % self.optimizer)

        return theta_opt, func_min

где scipy.optimize.minimize() имеет значения по умолчанию

scipy.optimize.minimize(fun, x0, args=(), method='L-BFGS-B', jac=None, bounds=None, 
tol=None, callback=None, options={'disp': None, 'maxcor': 10, 'ftol': 2.220446049250313e-09,
'gtol': 1e-05, 'eps': 1e-08, 'maxfun': 15000, 'maxiter': 15000, 'iprint': -1, 'maxls': 20})

согласно scipy docs.

Я хотел бы использовать именно тот оптимизатор, который показан выше в исходном коде GPR, но измените maxiter на большее число. Другими словами, я не хочу изменять поведение оптимизатора, кроме изменений, внесенных путем увеличения максимального числа итераций.

Проблема в том, что другие параметры, такие как obj_func, initial_theta, bounds установлены в исходном коде георадара и недоступны из объекта георадара.

Так я называю GPR, обратите внимание, что это в основном параметры по умолчанию, за исключением n_restarts_optimizer и ядра.

for kernel in kernels:
    gp = gaussian_process.GaussianProcessRegressor(
                    kernel              = kernel,
                    alpha               = 1e-10,
                    copy_X_train        = True,
                    optimizer           = "fmin_l_bfgs_b",
                    n_restarts_optimizer= 25,
                    normalize_y         = False,
                    random_state        = None)

1 ответ

Решение

Вы хотите расширить и / или изменить поведение существующего объекта Python, что звучит как хороший вариант использования наследования.

Решением может быть наследование от реализации scikit-learn и обеспечение вызова обычного оптимизатора с необходимыми аргументами. Вот набросок, но учтите, что это не проверено.

from functools import partial
from sklearn.gaussian_process import GaussianProcessRegressor
import scipy.optimize

class MyGPR(GaussianProcessRegressor):
    def __init__(self, *args, max_iter=15000, **kwargs):
        super().__init__(*args, **kwargs)
        self._max_iter = max_iter

    def _constrained_optimization(self, obj_func, initial_theta, bounds):
        def new_optimizer(obj_func, initial_theta, bounds):
            return scipy.optimize.minimize(
                obj_func,
                initial_theta,
                method="L-BFGS-B",
                jac=True,
                bounds=bounds,
                max_iter=self._max_iter,
            )
        self.optimizer = new_optimizer
        return super()._constrained_optimization(obj_func, initial_theta, bounds)

Для меня сработало следующее. Я использую наследование, а также переопределяю метод _constrained_optimization.

class MyGPR(GaussianProcessRegressor):
    def __init__(self, *args, max_iter=2e05, gtol=1e-06, **kwargs):
        super().__init__(*args, **kwargs)
        self._max_iter = max_iter
        self._gtol = gtol

    def _constrained_optimization(self, obj_func, initial_theta, bounds):
        if self.optimizer == "fmin_l_bfgs_b":
            opt_res = scipy.optimize.minimize(obj_func, initial_theta, method="L-BFGS-B", jac=True, bounds=bounds, options={'maxiter':self._max_iter, 'gtol': self._gtol})
            _check_optimize_result("lbfgs", opt_res)
            theta_opt, func_min = opt_res.x, opt_res.fun
        elif callable(self.optimizer):
            theta_opt, func_min = self.optimizer(obj_func, initial_theta, bounds=bounds)
        else:
            raise ValueError("Unknown optimizer %s." % self.optimizer)
        return theta_opt, func_min

Чтобы это работало, в дополнение к вашему обычному импорту вы также должны импортировать следующие

from sklearn.utils.optimize import _check_optimize_result
Другие вопросы по тегам