代码之家  ›  专栏  ›  技术社区  ›  quant

如何在tensorflow中实现nesterov的加速梯度下降?

  •  6
  • quant  · 技术社区  · 8 年前

    文件 tf.train.MomentumOptimizer 提供一个 use_nesterov 使用Nesterov加速梯度(NAG)方法的参数。

    但是,nag要求在当前变量以外的位置计算梯度,并且 apply_gradients 接口只允许传递当前渐变。所以我不太明白如何用这个接口实现nag算法。

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

    尤塞尔涅斯特罗夫 :如果为真,则使用Nesterov动量。见 Sutskever et al., 2013 . 这个 实现总是以 传递给优化器的变量。利用内斯特罗夫动量 变量跟踪调用的值 theta_t + mu*v_t 在报纸上。

    读完链接中的文章后,我有点不确定这个描述是否回答了我的问题。当接口不需要提供梯度函数时,如何实现NAG算法?

    2 回复  |  直到 8 年前
        1
  •  3
  •   P-Gn    8 年前

    DR

    tf对nesterov的实现实际上是原始公式的一个近似,对动量的高值有效。

    细节

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

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

    哪里 f 是我们的成本函数, θ t 我们当时的参数 t , μ 动力, λ 学习率; v t 是NAG的内部累加器。

    与标准动量的主要区别在于 θ t + μ.v t , γ T . 但正如你所说,Tensorflow只在 γ T . 那么诀窍是什么?

    技巧的一部分实际上在您引用的文档中提到:算法是跟踪 γ T +αv T , γ T . 另一部分来自对动量高值有效的近似。

    为了使累加器符合tensorflow的定义,让我们稍微改变一下纸上的符号。让我们来定义 a t = v t / λ . 更新规则稍微更改为

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

    (tf的这种变化的动机是现在 a 是一个纯梯度动量,与学习速率无关。这使得更新过程对 γ 一种在实践中普遍存在的可能性,但该论文没有考虑。

    如果我们注意到 ψ t = θ t + μ.λ.a t 然后

    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 ) 最后一种近似方法实际上更具争议性,对于具有频繁梯度切换的方向则不太有效。

    我们现在有了一个使用当前位置梯度的更新,规则非常简单——它们实际上是标准动量的规则。

    但是,我们希望 γ T 不是 ψ t . 这就是为什么我们要减去 μ.λ.a t+1 ψ t+1 在归还之前 ψ 在下一次呼叫时,它会在第一件事上再次被添加。

        2
  •  1
  •   quant    8 年前

    我在网上看不到这方面的任何信息,而且链接的报纸肯定没有帮助,所以我看了一下 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 其实现尝试通过假设新的梯度将由当前的平均梯度加上动量和平均梯度变化的乘积来估计nag中的“调整梯度”。我很想看到这方面的证据!

    下面将更详细地介绍如何在 张力流 根据测试。

    经典动量模式

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

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

    实际上,以上只是 grads_0 vars_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 测试用例。

    这个 _更新_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)
    
    推荐文章