2.7.2.2 基于梯度的方法

2.7.2.2.1 关于梯度下降的一些直觉

这里我们关注直觉,不是代码。代码在后面。

从根本上说,梯度下降在于在梯度方向上前进小步,即最陡峭梯度的方向。

固定步数梯度下降

状况良好的二元函数。

2.7.2.2 基于梯度的方法 - 图1

2.7.2.2 基于梯度的方法 - 图2

状况糟糕的二元函数。

状况糟糕问题的梯度下降算法的核心问题是梯度并不会指向最低点。

2.7.2.2 基于梯度的方法 - 图3

2.7.2.2 基于梯度的方法 - 图4

我们可以看到非常各向异性 (状况糟糕) 函数非常难优化。

带回家的信息: 条件数和预条件化

如果你知道变量的自然刻度,预刻度他们以便他们的行为相似。这与预条件化相关。

并且,很明显采用大步幅是有优势的。这在梯度下降代码中使用直线搜索

适应步数梯度下降

状况良好的二元函数。

2.7.2.2 基于梯度的方法 - 图5

2.7.2.2 基于梯度的方法 - 图6

状况糟糕的二元函数。

2.7.2.2 基于梯度的方法 - 图7

2.7.2.2 基于梯度的方法 - 图8

状况糟糕的非二元函数。

2.7.2.2 基于梯度的方法 - 图9

2.7.2.2 基于梯度的方法 - 图10

状况糟糕的极端非二元函数。

2.7.2.2 基于梯度的方法 - 图11

2.7.2.2 基于梯度的方法 - 图12

函数看起来越像二元函数 (椭圆半圆边框线), 最优化越简单。

2.7.2.2.2 共轭梯度下降

上面的梯度下降算法是玩具不会被用于真实的问题。

正如从上面例子中看到的,简单梯度下降算法的一个问题是,它试着摇摆穿越峡谷,每次跟随梯度的方法,以便穿越峡谷。共轭梯度通过添加摩擦力项来解决这个问题: 每一步依赖于前两个值的梯度然后急转弯减少了。

共轭梯度下降

状况糟糕的非二元函数。

2.7.2.2 基于梯度的方法 - 图13

2.7.2.2 基于梯度的方法 - 图14

状况糟糕的极端非二元函数。

2.7.2.2 基于梯度的方法 - 图15

2.7.2.2 基于梯度的方法 - 图16

在scipy中基于共轭梯度下降方法名称带有‘cg’。最小化函数的简单共轭梯度下降方法是scipy.optimize.fmin_cg():

In [5]:

  1. def f(x): # The rosenbrock函数
  2. return .5*(1 - x[0])**2 + (x[1] - x[0]**2)**2
  3. optimize.fmin_cg(f, [2, 2])
  1. Optimization terminated successfully.
  2. Current function value: 0.000000
  3. Iterations: 13
  4. Function evaluations: 120
  5. Gradient evaluations: 30

Out[5]:

  1. array([ 0.99998968, 0.99997855])

这些方法需要函数的梯度。方法可以计算梯度,但是如果传递了梯度性能将更好:

In [6]:

  1. def fprime(x):
  2. return np.array((-2*.5*(1 - x[0]) - 4*x[0]*(x[1] - x[0]**2), 2*(x[1] - x[0]**2)))
  3. optimize.fmin_cg(f, [2, 2], fprime=fprime)
  1. Optimization terminated successfully.
  2. Current function value: 0.000000
  3. Iterations: 13
  4. Function evaluations: 30
  5. Gradient evaluations: 30

Out[6]:

  1. array([ 0.99999199, 0.99998336])

注意函数只会评估30次,相对的没有梯度是120次。