2.7.3 使用scipy优化的现实指南

2.7.3.1 选择一个方法

2.7.3 使用scipy优化的现实指南 - 图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:

如果有噪音测量:

使用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]:

  1. optimize.check_grad(f, fprime, [2, 2])

Out[9]:

  1. 2.384185791015625e-07

也看一下scipy.optimize.approx_fprime()找一下你的错误。

2.7.3.4 合成练习

练习: 简单的 (?) 二次函数

2.7.3 使用scipy优化的现实指南 - 图2

用K[0]作为起始点优化下列函数:

In [2]:

  1. np.random.seed(0)
  2. K = np.random.normal(size=(100, 100))
  3. def f(x):
  4. return np.sum((np.dot(K, x - 1))**2) + np.sum(x**2)**2

计时你的方法。找到最快的方法。为什么BFGS不好用了?

练习:局部扁平最小化

2.7.3 使用scipy优化的现实指南 - 图3

2.7.3 使用scipy优化的现实指南 - 图4

考虑一下函数$exp(-1/(.1*x^2 + y^2)$。这个函数在(0,0)存在一个最小值。从起点(1,1)开始,试着在$1e-8$达到这个最低点。