2.7.3 使用scipy优化的现实指南
2.7.3.1 选择一个方法
没有关于梯度的知识:
- 一般来说,倾向于BFGS (scipy.optimize.fmin_bfgs()) 或 L-BFGS (), 即使你有大概的数值梯度
- 在状况良好的问题上,Powell () 以及 Nelder-Mead (scipy.optimize.fmin()), 都是在高维上效果良好的梯度自有的方法,但是 ,他们无法支持状况糟糕的问题。
有关于梯度的知识:
- BFGS (scipy.optimize.fmin_bfgs()) 或 L-BFGS (scipy.optimize.fmin_l_bfgs_b())。
- BFGS的计算开支要大于L-BFGS, 它自身也比共轭梯度法开销大。另一方面,BFGS通常比CG(共轭梯度法)需要更少函数评估。因此,共轭梯度法在优化计算量较少的函数时比BFGS更好。
带有Hessian:
- 如果你可以计算Hessian, 推荐牛顿法 (scipy.optimize.fmin_ncg())。
如果有噪音测量:
使用Nelder-Mead (scipy.optimize.fmin()) 或者 Powell (scipy.optimize.fmin_powell())。
2.7.3.2 让优化器更快
- 选择正确的方法 (见上面), 如果可以的话,计算梯度和Hessia。
- 可能的时候使用preconditionning。
- 聪明的选择你的起点。例如,如果你正在运行许多相似的优化,那么在其他结果上软启动。
- 如果你不需要准确,那么请放松并容忍
2.7.3.3 计算梯度
计算梯度甚至是Hessians的努力, 是枯燥的但是也是值得的。使用Sympy来进行象征计算将非常方便。
优化不能很好收敛的一个来源是计算梯度过程的人为错误。你可以用scipy.optimize.check_grad()来检查一下梯度是否正确。它返回给出的梯度与计算的梯度之间差异的基准:
In [9]:
optimize.check_grad(f, fprime, [2, 2])
Out[9]:
2.384185791015625e-07
也看一下scipy.optimize.approx_fprime()找一下你的错误。
2.7.3.4 合成练习
练习: 简单的 (?) 二次函数
用K[0]作为起始点优化下列函数:
In [2]:
np.random.seed(0)
K = np.random.normal(size=(100, 100))
def f(x):
return np.sum((np.dot(K, x - 1))**2) + np.sum(x**2)**2
计时你的方法。找到最快的方法。为什么BFGS不好用了?
练习:局部扁平最小化
考虑一下函数$exp(-1/(.1*x^2 + y^2)$。这个函数在(0,0)存在一个最小值。从起点(1,1)开始,试着在$1e-8$达到这个最低点。