如何在Tensorflow中实现Nesterov的加速梯度下降?

时间:2018-06-09 13:15:55

标签: python tensorflow machine-learning

tf.train.MomentumOptimizer的文档提供use_nesterov参数,以利用Nesterov的加速渐变(NAG)方法。

但是,NAG要求在不同于当前变量的位置处计算渐变,并且apply_gradients接口仅允许传递当前渐变。因此,我不太了解如何使用此接口实现NAG算法。

文档说明了以下有关实现的内容:

  

use_nesterov:如果是,请使用Nesterov Momentum。见Sutskever et al., 2013。这个   实现总是计算渐变的值   传递给优化器的变量。使用Nesterov Momentum制作   变量跟踪文章中名为theta_t + mu*v_t的值。

通过链接阅读了论文,我对这个描述是否回答了我的问题有点不确定。当界面不需要提供梯度函数时,如何实现NAG算法?

2 个答案:

答案 0 :(得分:2)

<强> TL; DR

TF对Nesterov的实现确实是原始公式的近似值,对于高动量值有效。

<强>详情

这是一个很好的问题。在本文中,NAG更新定义为

vt+1 = μ.vt - λ.∇f(θt + μ.vt)
θt+1 = θt + vt+1

其中f是我们的费用函数,θt我们的参数tμ动量,λ学习率; vt是NAG的内部累加器。

与标准动量的主要区别在于θt + μ.vt处的渐变使用,θt处的。但正如您所说,tensorflow仅使用θt处的渐变。那么诀窍是什么?

您引用的文档部分实际上提到了部分技巧:算法正在跟踪θt + μ.vt不是 θt。另一部分来自对高动量值有效的近似值。

让我们从纸上略微更改符号,以便累加器坚持使用tensorflow的定义。我们来定义at = vt / λ。更新规则稍有改动

at+1 = μ.at - ∇f(θt + μ.λ.at)
θt+1 = θt + λ.at+1

(TF的这种变化的动机是,现在a是一个纯粹的梯度动量,与学习率无关。这使得更新过程对λ的变化具有鲁棒性,这种可能性很常见练习,但文章没有考虑。)

如果我们注意到ψt = θt + μ.λ.at,那么

at+1 = μ.at - ∇f(ψt)
ψt+1 = θt+1 + μ.λ.at+1
    = θt + λ.at+1 + μ.λ.at+1
    = ψt + λ.at+1 + μ.λ.(at+1 - at)
    = ψt + λ.at+1 + μ.λ.[(μ-1)at - ∇f(ψt)]
    ≈ ψt + λ.at+1

最后的近似值适用于强动量值,其中μ接近1,因此μ-1接近于零,∇f(ψt)a相比较小 - 实际上这最后的近似值更具争议性,对频繁梯度切换的方向不太有效。

我们现在有一个使用当前位置的渐变的更新,规则非常简单 - 它们实际上是标准动量的那些。

但是,我们需要θt,而不是ψt。这就是我们在返回之前将μ.λ.at+1减去ψt+1的原因 - 并且为了恢复ψ,它会在下次调用时再次添加。{/ p>

答案 1 :(得分:1)

我在网上看不到这方面的任何信息,链接的文章肯定没有帮助,所以我看了unit tests for tf.train.MomentumOptimizer,从中我可以看到实施的测试经典动量和NAG模式。

摘要

var = var + accum * learning_rate * momentum
accum = accum * momentum + g
var = var - learning_rate * accum
var = var - accum * learning_rate * momentum

其中accum从0开始并在每一步都更新。以上是单元测试中配方的修改版本,我觉得有点混乱。以下是我对每个参数所代表的解释所安排的同一组方程式(虽然我可能错了):

average_grad_0 = accum # previous rolling average
average_grad_1 = accum * momentum + g # updated rolling average
grad_diff = average_grad_1 - average_grad_0
adjustment = -learning_rate * (grad_diff * momentum + average_grad_1)
var += adjustment
accum = average_grad_new

换句话说,在我看来,tensorflow的实现尝试猜测&#34;调整后的渐变&#34;在NAG中假设新的梯度将通过当前平均梯度加上动量的乘积和平均梯度的变化来估计。我很乐意看到这方面的证据!

以下是有关如何根据测试在tensorflow中实现经典和nesterov模式的更多细节。

经典动量模式

对于use_nesterov=False,基于doTestBasic函数,我们有以下初始参数:

learning_rate = 2.0
momentum = 0.9
var_0 = 1.0 # at time 0
grad = 0.1

实际上,上面只是grads_0vars_0数组的第一个元素,但我只关注单个值。对于随后的时间步,我们有

var_1 = 1.0 - (0.1 * 2.0)
var_2 = 1.0 - (0.1 * 2.0) - ((0.9 * 0.1 + 0.1) * 2.0)

我将其解释为含义;

var_1 = var_0 - (grad * learning_rate)
var_2 = var_1 - ((momentum * grad + grad) * learning_rate)

如果我们假设出于单元测试grad_0 == grad_1 == grad的目的,那么这作为经典动力的表达是有意义的。

Nesterov的加速梯度(NAG)模式

对于use_nesterov=True,我查看了_update_nesterov_momentum_numpy函数和testNesterovMomentum测试用例。

_update_nesterov_momentum_numpy函数具有以下定义:

  def _update_nesterov_momentum_numpy(self, var, accum, g, lr, momentum):
    var = var + accum * lr * momentum
    accum = accum * momentum + g
    var = var - lr * accum
    var = var - accum * lr * momentum
    return var, accum

并在单元测试中调用它:

    for t in range(1, 5):
      opt_op.run()
      var0_np, accum0_np = self._update_nesterov_momentum_numpy(
          var0_np, accum0_np, var0_np * 10, 2.0, 0.9)