本文介绍了为什么 scipy.optimize.minimize (默认)在不使用 Skyfield 的情况下报告成功?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

scipy.optimize.minimize 使用默认方法返回初始值作为结果,没有任何错误或警告消息.虽然使用 this answer 建议的 Nelder-Mead 方法解决了问题,但我想了解:

scipy.optimize.minimize using default method is returning the initial value as the result, without any error or warning messages. While using the Nelder-Mead method as suggested by this answer solves the problem, I would like to understand:

为什么默认方法返回作为答案的起点 - 有没有一种方法可以 在这种情况下避免这种行为?

Why does the default method returns the starting point as the answer - and is there a way I can avoid this behavior in this case?

注意,函数 separation 使用 python 包 Skyfield 来生成要最小化并不能保证平滑的值,这可能就是 Simplex 在这里更好的原因.

Note, the function separation uses the python package Skyfield to generate the values to be minimized which is not guaranteed smooth, which may be why Simplex is better here.

结果:

测试结果:[ 2.14159739] '正确':2.14159265359 初始:0.0

test result: [ 2.14159739] 'correct': 2.14159265359 initial: 0.0

默认结果:[ 10000.] '正确':13054 初始:10000

default result: [ 10000.] 'correct': 13054 initial: 10000

Nelder-Mead 结果:[ 13053.81011963] '正确':13054 初始值:10000

Nelder-Mead result: [ 13053.81011963] 'correct': 13054 initial: 10000

FULL OUTPUT using DEFAULT METHOD:
   status: 0
  success: True
     njev: 1
     nfev: 3
 hess_inv: array([[1]])
      fun: 1694.98753895812
        x: array([ 10000.])
  message: 'Optimization terminated successfully.'
      jac: array([ 0.])
      nit: 0

FULL OUTPUT using Nelder-Mead METHOD:
  status: 0
    nfev: 63
 success: True
     fun: 3.2179306044608054
       x: array([ 13053.81011963])
 message: 'Optimization terminated successfully.'
     nit: 28

这里是完整的脚本:

def g(x, a, b):
    return np.cos(a*x + b)

def separation(seconds, lat, lon):
    lat, lon, seconds = float(lat), float(lon), float(seconds) # necessary it seems
    place = earth.topos(lat, lon)
    jd = JulianDate(utc=(2016, 3, 9, 0, 0, seconds))
    mpos = place.at(jd).observe(moon).apparent().position.km
    spos = place.at(jd).observe(sun).apparent().position.km
    mlen = np.sqrt((mpos**2).sum())
    slen = np.sqrt((spos**2).sum())
    sepa = ((3600.*180./np.pi) *
            np.arccos(np.dot(mpos, spos)/(mlen*slen)))
    return sepa

from skyfield.api import load, now, JulianDate
import numpy as np
from scipy.optimize import minimize

data = load('de421.bsp')

sun   = data['sun']
earth = data['earth']
moon  = data['moon']

x_init = 0.0
out_g = minimize(g, x_init, args=(1, 1))
print "test result: ", out_g.x, "'correct': ", np.pi-1, "initial: ", x_init    # gives right answer

sec_init = 10000
out_s_def = minimize(separation, sec_init, args=(32.5, 215.1))
print "default result: ", out_s_def.x, "'correct': ", 13054, "initial: ", sec_init

sec_init = 10000
out_s_NM = minimize(separation, sec_init, args=(32.5, 215.1),
                 method = "Nelder-Mead")
print "Nelder-Mead result: ", out_s_NM.x, "'correct': ", 13054, "initial: ", sec_init

print ""
print "FULL OUTPUT using DEFAULT METHOD:"
print out_s_def
print ""
print "FULL OUTPUT using Nelder-Mead METHOD:"
print out_s_NM

推荐答案

1)

您的函数是分段常数(具有小规模的阶梯"模式).它并非处处可微.

Your function is piecewise constant (has small-scale "staircase" pattern).It is not everywhere differentiable.

函数在初始猜测时的梯度为零.

The gradient of the function at the initial guess is zero.

默认的 BFGS 优化器看到零梯度,并根据其标准(基于对输入函数的假设,在这种情况下不正确,例如可微性)将其确定为局部最小值.

The default BFGS optimizer sees the zero gradient and decides it is a local minimum by its criteria (which are based on assumptions about the input function that are not true in this case, such as differentiability).

基本上,完全平坦的区域会轰炸优化器.优化器在初始点周围的小而完全平坦的区域中探测函数,在那里一切看起来函数只是一个常数,所以它认为你给了它一个常数函数.因为你的函数不是处处可微的,所以有可能几乎所有的初始点都在这样的平坦区域内,这样就可以在选择初始点时不走运.

Basically, the exactly flat regions bomb the optimizer. The optimizer probes the function in the small exactly flat region around the initial point, where everything looks like the function is just a constant, so it thinks you gave it a constant function. Because your function is not differentiable everywhere, it is possible that almost all initial points are inside such flat regions, so that this can happen without bad luck in the choice of the initial point.

还要注意,Nelder-Mead 不能对此免疫——它只是碰巧它的初始单纯形大于楼梯的大小,因此它会在更大的点周围探测函数.如果初始单纯形小于楼梯大小,则优化器的行为将与 BFGS 类似.

Note also that Nelder-Mead is not immune to this --- it just happens its initial simplex is larger than the size of the staircase, so it probes the function around a larger spot. If the initial simplex would be smaller than the staircase size, the optimizer would behave similarly as BFGS.

2)

一般答案:局部优化器返回局部最优.这些是否与真正的最优值一致取决于函数的性质.

General answer: local optimizers return local optima. Whether these coincide with the true optimum depends on the properties of the function.

一般来说,要查看您是否陷入局部最优,请尝试不同的初始猜测.

In general, to see if you're stuck in a local optimum, try different initial guesses.

此外,在不可微函数上使用基于导数的优化器也不是一个好主意.如果函数在大"尺度上可微,则可以调整数值微分的步长.

Also, using a derivative-based optimizer on a non-differentiable function is not a good idea. If the function is differentiable on a "large" scale, you can adjust the step size of the numerical differentiation.

因为没有廉价/通用的方法来检查函数是否处处可微,所以没有进行这种检查——而是优化方法中的一个假设,必须由输入目标函数并选择的人来确保优化方法.

Because there is no cheap/general way to check numerically if a function is everywhere differentiable, no such check is done --- instead it is an assumption in the optimization method that must be ensured by whoever inputs the objective function and chooses the optimization method.

这篇关于为什么 scipy.optimize.minimize (默认)在不使用 Skyfield 的情况下报告成功?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-13 12:30