Правильное использование fmin_l_bfgs_b для подгонки параметров модели - PullRequest
6 голосов
/ 29 декабря 2011

У меня есть некоторые экспериментальные данные (для y, x, t_exp, m_exp), и я хочу найти «оптимальные» параметры модели (A, B, C, D, E) для этих данных, используя ограничение многомерный метод BFGS .Параметр E должен быть больше 0, остальные не ограничены.

def func(x, A, B, C, D, E, *args):
    return A * (x ** E) * numpy.cos(t_exp) * (1 - numpy.exp((-2 * B * x) / numpy.cos(t_exp))) +  numpy.exp((-2 * B * x) / numpy.cos(t_exp)) * C + (D * m_exp)

initial_values = numpy.array([-10, 2, -20, 0.3, 0.25])
mybounds = [(None,None), (None,None), (None,None), (None,None), (0, None)]
x,f,d = scipy.optimize.fmin_l_bfgs_b(func, x0=initial_values, args=(m_exp, t_exp), bounds=mybounds)

Несколько вопросов:

  1. Должна ли моя формулировка модели func включать мою независимую переменную x илидолжен ли он быть предоставлен из экспериментальных данных x_exp как часть *args?
  2. Когда я запускаю приведенный выше код, я получаю ошибку func() takes at least 6 arguments (3 given), которую я предполагаю равной x, и мои два * аргумента... Как мне определить func?

РЕДАКТИРОВАТЬ: Благодаря ответу @ zephyr теперь я понимаю, что цель состоит в том, чтобы минимизировать сумму квадратов невязок, а не фактическую функцию.Я получил следующий рабочий код:

def func(params, *args):
    l_exp = args[0]
    s_exp = args[1]
    m_exp = args[2]
    t_exp = args[3]
    A, B, C, D, E = params
    s_model = A * (l_exp ** E) * numpy.cos(t_exp) * (1 - numpy.exp((-2 * B * l_exp) / numpy.cos(t_exp))) +  numpy.exp((-2 * B * l_exp) / numpy.cos(theta_exp)) * C + (D * m_exp)
    residual = s_exp - s_model
    return numpy.sum(residual ** 2)

initial_values = numpy.array([-10, 2, -20, 0.3, 0.25])
mybounds = [(None,None), (None,None), (None,None), (None,None), (0,None)]

x, f, d = scipy.optimize.fmin_l_bfgs_b(func, x0=initial_values, args=(l_exp, s_exp, m_exp, t_exp), bounds=mybounds, approx_grad=True)

Я не уверен, что границы работают правильно.Когда я указываю (0, Нет) для E, я получаю флаг запуска 2, аварийное завершение.Если я установлю его (1e-6, None), он будет работать нормально, но выберет 1e-6 в качестве E. Правильно ли я определяю границы?

1 Ответ

12 голосов
/ 29 декабря 2011

Я не хотел пытаться выяснить, какую модель вы используете, так что вот простой пример, подходящий к строке:

x_true = arange(0,10,0.1)
m_true = 2.5
b_true = 1.0
y_true = m_true*x_true + b_true

def func(params, *args):
    x = args[0]
    y = args[1]
    m, b = params
    y_model = m*x+b
    error = y-y_model
    return sum(error**2)

initial_values = numpy.array([1.0, 0.0])
mybounds = [(None,2), (None,None)]

scipy.optimize.fmin_l_bfgs_b(func, x0=initial_values, args=(x_true,y_true), approx_grad=True)
scipy.optimize.fmin_l_bfgs_b(func, x0=initial_values, args=(x_true, y_true), bounds=mybounds, approx_grad=True)

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

Важная вещь, которую вы ошиблись, заключается в том, что почти для всех функций оптимизации 'x' и 'x0' относятся к параметрам, по которым вы оптимизируете - все остальное передается в качестве аргумента.Также важно, чтобы ваша функция fit возвращала правильный тип данных - здесь нам нужно одно значение, некоторые подпрограммы ожидают вектор ошибки.Кроме того, вам нужен флаг приблизительно, если вы не хотите вычислять градиент аналитически и предоставлять его.

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