Introduction to Optimization(二):基于梯度的优化

这篇文章主要讲:

  • 梯度下降
  • 梯度最速降

梯度下降

相信这个对于大部分人来说并不陌生,听过吴恩达公开课的都知道(escape….)
我们知道梯度方向是函数下降最快的方向(书上有证明).梯度下降就是沿着梯度负方向构造一个点: xxαxx (粗体表示列向量),将其泰勒展开我们有

f(xxαxx)=f(xx)α||f(xx)||2+o(α)

那么我们有当 α 足够小的时候,有 f(xxαxx)<f(xx)

因此我们可以用如下迭代公式来求极小值点

xxk+1=xxkαkf(xxk)

αk 称为步长.

梯度最速降方法

这其实只是改进 αk 的选择方法. αk 选择方式如下

αk=argminα0f(xxkαkxxk)

即使得 f(xxαxx) 得到最大的下降值.

注意 注意到上面的函数只是一个一维优化因此可以用前面的Introduction to Optimization:一维最优化方法
来优化,其中 αk 并不需要很好的精度

停机准则

这里给出几个停机准则:

  1. |fk+1fk|max{1,|fk|}<ϵ

  2. ||xxk+1xxk||max{1,||xxk||}<ϵ

  3. ||fk||<ϵ

收敛性说明

这里不加证明的记录几条关于最速降的性质

  1. 最速降产生的序列 xx1,xx2,, 梯度向量前后正交
  2. 最速降算法 任意初始值 xx0 总是收敛到极小值点.
  3. 对于固定步长的算法,当且仅当 0<α<2λmax(QQ) 时 任意初始点都收敛.

收敛阶

最速降算法收敛阶为 1阶 收敛很慢

算法实现

完整代码在这里https://github.com/DylanFrank/optimize

def fast_gradient(fun, grad, x0, tol=1e-7, max_iter=500):
    phi = lambda alpha, x: fun(x - alpha * np.array(grad(x)))  # 最速降参数
    iters = max_iter
    while iters > 0:
        iters -= 1
        res = minimize_scalar(phi, method='brent', args=x0, tol=1e-5)
        x_next = x0 - res.x * np.array(grad(x0))
        if is_stop(x_next, x0, tol):
            break
        x0 = x_next
    return OptimizeResult({'x': x0, 'fun': fun(x0), 'jac': grad(x0), 'nit': max_iter - iters})

只有几行,代码非常短
用rosenbrock 函数来测试一下

my opt
  fun: 3.5307940531271921e-11
 jac: array([  7.90266005e-06,   1.98987364e-06])
 nit: 17613
   x: array([ 1.00000594,  1.00001189])
scipy.opt.minimize

      fun: 9.817296647123749e-14
 hess_inv: array([[ 0.48098005,  0.95985458],
       [ 0.95985458,  1.92027267]])
      jac: array([ -8.75835534e-06,   4.59236316e-06])
  message: 'Optimization terminated successfully.'
     nfev: 42
      nit: 35
     njev: 42
   status: 0
  success: True
        x: array([ 1.00000021,  1.00000045])

用最速降方法迭代了接近 20000次而用scipy.optimize 的NM单纯形只用了35次简直是天壤之别难怪optimize 里没有实现。别急没多久就要学到 N-M单纯形了

转载请注明本文链接 http://blog.csdn.net/Dylan_Frank/article/details/78220959

你可能感兴趣的:(math)