skopt: Как динамически изменять границы при оптимизации?
Я только начал использовать skopt, поэтому перенаправляйте меня к любому базовому руководству, которое я мог пропустить. Во всяком случае, вот оно:
У меня есть проблема оптимизации, когда я вычисляю спектр с двумя пиками с помощью сложной физической модели, а затем извлекаю его лоренцевский профиль (т.е. 6 параметров, по 3 на пик). Затем я настроил функцию стоимости, которая вычисляет квадрат разницы между рассчитанными параметрами и экспериментальным, так что я получаю f(x), которая принимает массив и возвращает скаляр (если я правильно понял, это то, что требует gp_minimize).
Я установил ограничения проблемы, используя следующее:
dim1=Real(name="A1", low=1, high=100)dim2=Real(name="A2", low=1, high=200)
размеры = [dim1, dim2,...], но в моей конкретной системе A2 ограничен 2*A1. Есть ли способ использовать это в ограничениях, подобных показанным выше, чтобы избежать поиска во множестве «нефизических» пространств параметров? В моем конкретном случае оценка модели занимает очень много времени, поэтому было бы очень полезно избежать ненужных вычислений :)
Заранее спасибо за вашу помощь!
Бест, Крис
1 ответ
На данный момент не представляется возможным указать этот тип зависимости между размерами пространства поиска. Однако вы можете включить ограничение в цель, передаваемую оптимизатору.
В приведенном ниже примере «истинная» (и дорогостоящая) цель оценивается только при соблюдении ограничения. В противном случае немедленно возвращается высокое значение.
На рисунке все слева от пунктирной линии нарушает
a2 <= 2*a1
. Красный крест - истинный минимум цели f, а черные точки - объективные оценки. Из-за высоких объективных значений слева от строки фокус поиска находится в допустимой части области поиска. Конечно, также могут быть оценки в недопустимом подпространстве (во время первоначальной случайной выборки или при «изучении» вместо «эксплуатации»), но они не будут включать оценку дорогостоящей цели.
f
.
import numpy as np
from matplotlib import pyplot as plt
from skopt import gp_minimize
from skopt.space import Real
from skopt.utils import use_named_args
# search space
dimensions = [Real(name='a1', low=1, high=10),
Real(name='a2', low=1, high=10)]
# expensive target function to minimize
def f(a1, a2):
x1 = a1 - 4.5
x2 = a2 - 7
return 1.5*x1**2 + x2**2 - 0.9*x1*x2
# objective function passed to optimizer incorporates constraint
@use_named_args(dimensions)
def objective(a1, a2):
# if constraint violated quickly return a high value ...
if a2 > 2*a1:
return 1e4
# ... otherwise expensive target can be evaluated
else:
return f(a1, a2)
# run optimization
res = gp_minimize(objective, dimensions, n_calls=50, n_initial_points=20, random_state=92)
# evaluate f on regular grid for plotting
a1_grid = np.linspace(0, 10, 50)
a2_grid = np.linspace(0, 10, 50)
f_grid = np.array([f(i, j) for j in a2_grid for i in a1_grid]).reshape(
len(a1_grid), len(a2_grid))
# visualize results
fig, ax = plt.subplots()
ax.set_xlabel('a1')
ax.set_ylabel('a2')
# contours of f
ax.contourf(a1_grid, a2_grid, f_grid, 20)
# true minimum
ax.plot(4.5, 7, 'rx')
# constraint
ax.plot([0, 5], [0, 10], 'k--')
# evaluations
for x in res.x_iters:
ax.plot(x[0], x[1], 'k.')