uho*_*hoh 4 python minimize scipy skyfield
scipy.optimize.minimize使用默认方法将返回初始值作为结果,而不会出现任何错误或警告消息。在使用此答案建议的Nelder-Mead方法解决问题时,我想了解:
为什么默认方法会在不警告起点的情况下返回错误答案作为答案-并且 在这种情况下,有什么方法可以防止“没有警告就错误回答”避免这种情况?
请注意,该函数separation使用python软件包Skyfield生成无法保证平滑的最小化值,这可能就是为什么Simplex在此处更好的原因。
结果:
测试结果:[ 2.14159739 ]'正确': 2.14159265359初始值:0.0
默认结果:[ 10000。 ]“正确”:13054初始值: 10000
Nelder-Mead结果:[ 13053.81011963 ]'正确': 13054初始值: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
Run Code Online (Sandbox Code Playgroud)
这是完整的脚本:
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
Run Code Online (Sandbox Code Playgroud)
1)
您的函数是分段常量(具有小规模的“楼梯”模式)。并非到处都是可区分的。
初始猜测时函数的梯度为零。
默认的BFGS优化器会看到零梯度,并根据其标准将其确定为局部最小值(基于关于输入函数的假设,这种假设在这种情况下是不正确的,例如微分)。
基本上,完全平坦的区域会轰炸优化器。优化器在初始点附近的一个很小的平坦区域中探测该函数,在该区域中一切看上去都像一个常数,因此认为您给了它一个常数。因为您的功能在任何地方都无法微分,所以几乎所有的初始点都可能在这样平坦的区域内,因此在选择初始点时不会出现运气不好的情况。
还要注意,Nelder-Mead 不能幸免于此---恰好它的初始单纯形大于阶梯的大小,因此它会在更大的位置附近探测功能。如果初始单纯形小于阶梯尺寸,则优化器的行为与BFGS类似。
2)
通用答案:局部优化器返回局部最优值。它们是否与真正的最优值一致取决于函数的属性。
通常,要查看您是否陷入局部最优状态,请尝试不同的初始猜测。
同样,对不可微函数使用基于导数的优化器也不是一个好主意。如果该函数可以“大”微分,则可以调整数值微分的步长。
因为没有便宜/通用的方法可以数字地检查函数是否到处都是可微的,所以不会进行这种检查---相反,这是优化方法中的一种假设,必须由输入目标函数并选择优化方法的人来确保。
| 归档时间: |
|
| 查看次数: |
2636 次 |
| 最近记录: |