使用不等式约束和界限优化非标量函数

Optimize non-scalar function with inequality constraint and bounds

我正在 scipy 中寻找优化方法,它允许我最小化受约束 g(x,y) 约束的对象函数 f(x,y)(returns 向量) < 0.1 和 x 和 y 的附加界限。

我已经尝试用 scipy.optimize.least_squares、scipy.optimize.leastsq 和 scipy.optimize.minimize 来解决我的问题。问题是 leastsq 和 least_squares 允许对象函数是非标量的,但不给我实现约束(仅限边界)的可能性。另一方面,最小化让我有可能同时实现约束和边界,但是 f(x,y) 必须 return 是一个标量。因此,我正在寻找一种将两者结合起来的解决方案。有谁知道是否存在这样的东西?

我要最小化的函数是

def my_cost(p,f_noise):
    x,y = p[0], p[1]
    f = #some function that returns a 3x1 array
    return (f - fnoise)**2

我用 least_squares 方法做到了。

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 数组的方法。

非常感谢任何帮助! 为你的时间干杯!

根据 docs,objective 函数在使用 scipy.optimize.minimize 时必须 return 浮点数,而使用 scipy.optimize.least_squares 时则不能使用约束。 在这种情况下,您必须了解您的最小化目的。最小化差异向量(如 f-f_noise)等同于最小化 element-wise 差异及其总和。因此,一个实用的解决方案是最小化 f(x,y)g(x) 的已定义 p-norm。我建议使用正方形 L2-norm 因为它与您在成本函数中尝试的非常相似并且简单且稳定(相比之下其他规范)。

你可以取范数的平均值得到 Mean Squared Error (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)