Я ищу метод оптимизации в scipy, который позволяет мне минимизировать объектную функцию f (x, y) (возвращает вектор) с учетом ограничения g (x, y) <0,1 и дополнительных ограничений на x и y.
Я попытался решить свою проблему с помощью scipy.optimize.least_squares, scipy.optimize.leastsq и scipy.optimize.minimize. Проблема в том, что наименьшие квадраты и наименьшие_квадраты позволяют объектной функции быть нескалярной, но не дают мне возможности реализовать ограничение (только границы). с другой стороны, минимизация дает мне возможность реализовать как ограничение, так и границы, но f(x,y) должен возвращать скаляр. Следовательно, я ищу решение, которое сочетает в себе оба. Кто-нибудь знает, существует ли нечто подобное?
Функция, которую я хочу свести к минимуму,
def my_cost(p,f_noise):
x,y = p[0], p[1]
f = #some function that returns a 3x1 array
return (f - fnoise)**2
Я сделал это с помощью метода наименьших квадратов.
opti.least_squares(my_cost, p0[:], args = (f_noise,),gtol=1e-2, bounds=bounds)
Но здесь у меня проблема, что я не могу ограничить переменные в p. Мне нужно ограничить p, чтобы он выполнял
def constraint(p)
x = p[0]
return fy(x) - y <= 0.1 #variable y therefore becomes a function of variable x
Чтобы реализовать ограничение, я протестировал функцию минимизации scipy.
opti.minimize(my_cost, p0[:], args = (f_noise,), bounds = bounds, constraints = {'type': 'eq', 'fun': constraint})
Но здесь я не могу найти способ, чтобы my_cost и f_noise были массивами 3x1.
За любую помощь я очень благодарен! Рад за ваше время!
Согласно документы, целевая функция должна возвращать число с плавающей запятой при использовании scipy.optimize.minimize
, тогда как с scipy.optimize.least_squares
вы не можете использовать ограничения.
В этом случае вы должны осознавать свою цель минимизации. Минимизация разностного вектора (например, f-f_noise
) эквивалентна минимизации поэлементных разностей и, следовательно, их суммы. Поэтому практическим решением было бы минимизировать определенную p-норму ваших f(x,y)
и g(x)
. Я предлагаю квадрат L2-норма, поскольку он очень похож на то, что вы пытаетесь использовать в своей функции стоимости, и он прост и стабилен (по сравнению с другими нормами).
Можно усреднить норму и получить Среднеквадратическая ошибка (MSE):
Применяя предыдущие концепции, вы получаете следующий код:
import numpy as np
from scipy.optimize import minimize
# define fy
def fy(x):
return x**2 * np.array([[.1],[.2],[.3]]) # some function that returns a 3x1 array
# objective func
def f(p, f_noise):
x, y = p[0], p[1]
f = x * y * np.array([[1],[2],[3]]) # some function that returns a 3x1 array
return np.linalg.norm(f - f_noise, 2)**2
# constraint
def g(p):
x = p[0]
diff_norm = np.linalg.norm(fy(x) - y)
return threshold - diff_norm
# init
f_noise = np.array([[.1],[.2],[.3]])
p0 = np.array([1, 0.5])
bounds = ((0,2),(0,2))
y = np.array([[.9],[.7],[.2]])
threshold = 0.1 # make sure to choose an adequate threshold
# minimize
result = minimize(f, p0,
args = (f_noise,),
bounds = bounds,
constraints = {'type': 'ineq', 'fun': g})
# print result
print(result)
Большое спасибо, СуперКогито. Кажется, это работает, хотя я все еще провожу некоторые тесты. У меня есть один вопрос к этому решению: ограничение выбирается через порог. Разве это не уменьшает найденное решение до наилучшего значения, где порог = diff_norm вместо наилучшего значения для diffnorm < порога? т.е. в вашем решении я понимаю, что ограничение составляет g (x, y) = 0,1 вместо g (x, y) <0,1. Мне кажется, это какое-то лагранжево ограничение.
Это больше зависит от характера вашей проблемы. Вам решать, какой тип ограничения (равенство или неравенство) более эффективен в вашем случае. Я думаю, что неравенство, вероятно, быстрее, потому что тривиально легче найти значение ниже порога по сравнению с поиском значения, равного порогу.
Да, точно. Думаю будет быстрее. Я хотел бы ограничить минимизацию всеми точками, где g(x,y) <0,1. Но насколько я понимаю, в настоящее время код ищет решение, где g(x,y) ближе всего к 0,1. Но я не знаю, как реализовать ограничение неравенства.
В моем примере я использую ограничение неравенства. Я определил это в этой строке constraints = {'type': 'ineq', 'fun': g}
. Поэтому минимизация ищет решение, следя за тем, чтобы возврат ограничения был положительным: g(p) >= 0 -> threshold - diff_norm >= 0 -> threshold >= diff_norm
. Прочтите раздел ограничений здесь и обратитесь к это.
Ах идеально. Я искал команду «ineq», но, должно быть, просмотрел ее. Большое спасибо, Когито! Вы мне очень помогли!
Добро пожаловать :) рассмотрите возможность принятия ответа, если он помог.
Спасибо за очень полезный и быстрый ответ, SuperKogito! Это восхитительно! Я проверю это и отвечу позже, решило ли это мою проблему.