Оптимизируйте нескалярную функцию с ограничением неравенства и границами

Я ищу метод оптимизации в 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.

За любую помощь я очень благодарен! Рад за ваше время!

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
687
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Согласно документы, целевая функция должна возвращать число с плавающей запятой при использовании 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)

Спасибо за очень полезный и быстрый ответ, SuperKogito! Это восхитительно! Я проверю это и отвечу позже, решило ли это мою проблему.

Simon 14.06.2019 11:40

Большое спасибо, СуперКогито. Кажется, это работает, хотя я все еще провожу некоторые тесты. У меня есть один вопрос к этому решению: ограничение выбирается через порог. Разве это не уменьшает найденное решение до наилучшего значения, где порог = diff_norm вместо наилучшего значения для diffnorm < порога? т.е. в вашем решении я понимаю, что ограничение составляет g (x, y) = 0,1 вместо g (x, y) <0,1. Мне кажется, это какое-то лагранжево ограничение.

Simon 14.06.2019 17:04

Это больше зависит от характера вашей проблемы. Вам решать, какой тип ограничения (равенство или неравенство) более эффективен в вашем случае. Я думаю, что неравенство, вероятно, быстрее, потому что тривиально легче найти значение ниже порога по сравнению с поиском значения, равного порогу.

SuperKogito 15.06.2019 21:16

Да, точно. Думаю будет быстрее. Я хотел бы ограничить минимизацию всеми точками, где g(x,y) <0,1. Но насколько я понимаю, в настоящее время код ищет решение, где g(x,y) ближе всего к 0,1. Но я не знаю, как реализовать ограничение неравенства.

Simon 15.06.2019 22:10

В моем примере я использую ограничение неравенства. Я определил это в этой строке constraints = {'type': 'ineq', 'fun': g}. Поэтому минимизация ищет решение, следя за тем, чтобы возврат ограничения был положительным: g(p) >= 0 -> threshold - diff_norm >= 0 -> threshold >= diff_norm. Прочтите раздел ограничений здесь и обратитесь к это.

SuperKogito 15.06.2019 22:29

Ах идеально. Я искал команду «ineq», но, должно быть, просмотрел ее. Большое спасибо, Когито! Вы мне очень помогли!

Simon 15.06.2019 22:42

Добро пожаловать :) рассмотрите возможность принятия ответа, если он помог.

SuperKogito 16.06.2019 11:05

Другие вопросы по теме