如何模拟不预见边界的最小化器的边界?

How to simulate bounds for minimizers that do not foresee bounds?

我有一个优化问题,我想使用 scipy.optimize.minimize 包,即不预见任何约束或界限的方法之一,如 'nelder-mead'、'powell'、 'cg'、'bfgs'、newton-cg'、'dogleg'、'trust-ncg' - 参见:minimize exception about bounds and constraints.

我想通过在我的成本函数周围添加一个包装器来自己引入边界:

这个包装器被优化器调用并将参数传递给我想要优化的成本函数。成本函数比 returns 一个值给包装器。

如果优化器使用超出参数允许范围的参数调用包装器,包装器随后会向成本函数的结果添加一些额外的 'penalty' 并传递惩罚和成本函数的结果返回到优化器。

我的问题是:

优化是否会正常工作(这意味着:它会以更高的概率找到我的成本函数的绝对最小值),如果我有一个像这样的二元惩罚函数(仅显示边界的上限) ):

if parameter > upperBound:
    penalty = 1.e6
else:
    penalty = 0.0

或者使用更平滑的惩罚函数(模拟 lipschitz 连续函数之类的东西)更好,比如 e。 G。平移平方函数:

if parameter > upperBound:
    penalty = VERY_HIGH_NUMBER * (parameter - upperBound)**2
else:
    penalty = 0.0

如果使用更平滑的惩罚函数更好,是否有'best practizes'这些函数(例如使用 sigmoid 函数或平方函数等)?

我通常会转换参数 space,使 -Inf 对应于最低值,而 +Inf 对应于最高值,例如如果 sigmoid 函数在顶部和底部有界,则可以使用它,或者如果你只是想要一些东西是积极的,则可以使用 "log of 1+exp" (不确定这个的规范名称)。天真的版本是:

def sigfn(x):
  return 1 / (1 + exp(-x))

def logexpfn(x):
  return log1p(exp(x))

但您可能需要特别小心地处理大值,因为超过 ~700 值的值会导致 exp 溢出。所以功能可以扩展为:

def sigfn(x):
  if x < -36:
    return exp(x)
  return 1 / (1 + exp(-x))

def logexpfn(x):
  if x > 36:
    return x
  return log1p(exp(x))

我使用 36,因为这是我们失去精度的点,即 exp(37) * float_info.epsilon > 1

如果你只是想要一个上限,你可以使用这些来做:

def optfn(param):
  param = upperValue - logexpfn(-param)

或者任何对你的代码有意义的东西。这显然比直接使用东西更尴尬,但这是一种非常通用的技术并且普遍适用