Lec6.2

Newton's method

好的,接下来我们将讨论牛顿法,这是你在学习优化课程时通常会接触到的经典的二阶优化方法,在你开始学习迭代优化时,你通常首先会学习最小二乘法,然后是梯度下降法,接着就是牛顿法。

因此,我想在这里突出一下牛顿法,但在我介绍它之前,我想强调一下,但尽管牛顿法在很多情况下是传统优化的正确方法,而且它确实构成了大量经典的凸优化方法的基础,但在深度学习中并未被广泛使用,原因我们稍后会讨论。

但让我们直接开始,讲解一下牛顿法是什么:

牛顿法是另一种更新方式,牛顿法的思想是我们将进行与梯度下降相似的更新因此,我们将有我们的参数减去一些,你知道,本质上是梯度的某种缩放(scale the gradient),所以我们将在这里有我们之前的梯度项,但我们将对梯度进行缩放,我们实际上也将有一个步长,如我们之前所做,但我们将通 一个矩阵对这个梯度进行缩放,然后我们将在这个梯度上行进一步。

我会回到这个前面的幻灯片,我们在这个函数中知道最优值就在这里,所以如果我们从这里开始,你知道,这个函数在不同的方向和不同的大小上的这种性质,导致了梯度并不与通向最优值的正确方向很对齐,结果对于二次函数,或者当它们被近似为二次函数时,对于一般的凸函数,你可以直接用所谓的Hessian矩阵来纠正这个问题,它基本上是这个函数的一组二阶导数。

好的,让我写出我是什么意思:在牛顿法中,我们将用一个矩阵来缩放这个梯度,我将这样写出来:

θt+1=θtα(θ2f(θt))1θf(θt)\theta_{t+1}=\theta_{t}-\alpha(\nabla_\theta^2f(\theta_t))^{-1}\nabla_\theta f(\theta_t)

这里的α\alpha是一个步长参数,用于控制我们在每一步中沿着最陡下降方向移动的距离,而Hessian矩阵则表示函数在该点的曲率。矩阵的逆表示我们将这些曲率考虑进去,从而对步长进行了校正。

Hessian矩阵是一个二阶导数矩阵,表示了函数的曲率。它的每个元素是函数关于两个参数的二阶偏导数。Hessian矩阵的逆矩阵用于调整函数的梯度,从而提高迭代步骤的效率。

好的,这就是这个方法的基本思想。

再次,我实际上并没有故意详细地覆盖这个,因为它并不那么相关,但我想强调的是,实际上,我也终于提到,如果你采取步长 α=1\alpha = 1,这实际上对应于所谓的全牛顿步骤,但如果你采取的 α<1\alpha < 1,这就是所谓的阻尼牛顿步骤。

Illustration of Newton's method

我想要讨论的重点是这个幻灯片,也就是说如下内容。结果表明,对于一个二次函数(记住我们在前面的幻灯片中的这个函数,这是一个二次函数,只有一个二次项和一个线性项,就像我们两个幻灯片前提到的那样,它有一个二次项和一个线性项),牛顿法实际上给出了一个精确的解,对于一个二次函数,如果我们选择α=1\alpha = 1,牛顿法实际上将会以完全正确的方式找到解。

所以你在这里看到的是我们正跟随着的步骤,它们都准确地指向了最优点。就像在每一点,我们都直接朝向最优点前进。事实上,如果我们取步长α=1\alpha = 1(我这里展示的是α=0.5\alpha = 0.5,所以我们从这里开始,走到最优点的一半,然后再走一半,以此类推),我们就会直接达到这里的最优点。

这点其实不难证明,你只需对牛顿法的更新进行观察。如果我们的函数f(θ)f(\theta)是二次的,那么我们实际上可以求解这个梯度ablaθf(θ)abla_{\theta}f(\theta)。这个梯度在这种情况下实际上等于pθ+qp\theta+q。我们实际上可以精确求解这个,因为我们只需设定θ\theta^*等于p1q-p^{-1}q

实际上,这里的pp就是我们的Hessian,qq就是我们的梯度,或者说这个更新在消除了一些项后,给出了这个精确的表达式,你应该得到你的下一个表达式实际上等于这个。你可以验证这一点,这实际上很容易证明。

这是梯度,但是当你用Hessian(在这种情况下是pp)乘以梯度时,然后形成一个牛顿更新,项就会消去,所以你就得到了这个精确的解。你可以把这个作为一个练习。

但是关键是,牛顿法将会为二次函数找到精确的解,而这对我们的讨论而言,真正重要的一点我想强调的是,这意味着在某种意义上,牛顿法正在找到函数下降的正确方向。也就是说,它总是直接朝着我们的最优点前进,这与梯度下降形成鲜明的对比,梯度下降是在这个函数周围跳来跳去,它没有找到通往最优点的实际的、正确的、校正过的方向,而牛顿法做到了。

虽然牛顿法为优化问题提供了一个非常精确的方法,但在处理深度学习问题时,由于参数的数量和Hessian矩阵的计算复杂性,这种方法变得不实用。即使有一些二阶优化方法的近似版本存在,但我个人对它们在深度学习上的应用保持怀疑态度。

Momentum

好的,现在让我们开始讨论深度学习中非常常见的第一种方法,即动量(Momentum)。可以将动量视为试图在梯度下降法和牛顿法之间找到一种折中的方法,但实际上,它更接近梯度下降法,因为它只是一个纯粹的一阶方法,只使用梯度项,其复杂性与梯度下降法相同。

动量更新的思想是,在我们的参数之外,我们还要携带一些我们称之为动量项。这些动量项是将要帮助我们比仅使用梯度本身做出更好的更新的额外项。

动量的概念是:

  • 在梯度下降中,如果我们使用较大的步长,往往会在目标函数的优化路径上来回跳跃。这种跳跃可能并不有效,因为我们的梯度方向可能会在相邻的几步中有大的变化。然而,如果观察多个梯度更新步骤,我们可能会发现一些梯度方向实际上是类似的。也就是说,这些梯度方向在某种程度上重复了我们的更新步骤。在这种情况下,我们可能会希望能够在这些相似的梯度方向之间做出平均,从而找到一个更好的更新方向。这就是动量项的作用:它在一定程度上对过去的梯度进行平均,这样我们就可以沿着这个平均方向进行更新

我应该先提到的一点是,动量有很多种写法,但我喜欢这种写法,因为它强调了我们在参数之间进行平均的事实,而且也保持了动量和梯度的相似的规模

ut+1=βut+(1β)f(θt)u_{t+1}=\beta u_{t}+(1-\beta) f(\theta_t)

好的,所以这将是某种的,其中β\beta这里是一个标量值,通常小于1。实际上,有一些比1大的疯狂的动量方案,但这并不是我们在这里要做的。所以我们将对我们之前的动量项进行缩小,然后我们将添加另外一部分,1β1-\beta,作为我们的梯度。这将是我们动量项的更新。所以动量项所做的就是计算我们的梯度的指数移动平均,因为它最终将成为我们之前看到的过去的梯度的几何级数。或许我会稍后写下这个。

这个公式通常也会以其他形式书写。所以人们通常会写出β\beta这里,但是在缩放上没有β\beta,或者你在缩放那里添加α\alpha。如果你遇到动量的实现,你就必须查找一下它是如何实现的,但这就是我将要写的方式。我喜欢这样做的原因是,它保持了你在这里与我们的梯度的相似规模。因为它是我们梯度的指数移动平均,所以它保持了相同的规模。

现在,为了看到这一点,只需要为这一个案例显式地写出来。我不会在这之后再做这个,

我们来看看 ut+1u_{t+1} 到底是什么呢?

ut+1=(1β)gradient of current term+βutu_{t+1} = (1 - \beta) \cdot \text{gradient of current term} + \beta \cdot u_{t}

但我们也要展开 utu_{t}

ut=βut1+(1β)gradient at time t1u_{t} = \beta \cdot u_{t-1} + (1 - \beta) \cdot \text{gradient at time } t - 1

所以,

ut+1=(1β)gradient of current term+β[(1β)gradient at time t1+βut1]u_{t+1} = (1 - \beta) \cdot \text{gradient of current term} + \beta \cdot [(1 - \beta) \cdot \text{gradient at time } t - 1 + \beta \cdot u_{t-1}]

继续展开 ut1u_{t-1},我们可以得到:

ut+1=(1β)gradient of current term+β[(1β)gradient at time t1+β[(1β)gradient at time t2+βut2]]u_{t+1} = (1 - \beta) \cdot \text{gradient of current term} + \beta \cdot [(1 - \beta) \cdot \text{gradient at time } t - 1 + \beta \cdot [(1 - \beta) \cdot \text{gradient at time } t - 2 + \beta \cdot u_{t-2}]]

依此类推,我们在这里计算的实际上是过去梯度的一种几何求和或者说是加权的历史。

所以这是为什么我们把它叫作动量,因为你可以想象,这在某种意义上是在物理中保持动量的一种方式。我们不是只看我们现在的梯度,而是看到过去的梯度,我们在这里继续前进,这就是我们的动量。所以这就是为什么我们称其为动量。我认为这是一个好的解释。但是动量更像一种指数加权的移动平均,对吧?我们在这里有这样的权重。但这不是一种精确的平均,因为如果我们在这里加起来,那么将会是一个几何级数,它是有上限的。所以我们在这里有一些指数减小的权重,但是我们在这里做的实际上是一个加权的平均。

这就是动量的全部。


Illustration of momentum

现在,我展示一下我们之前的梯度下降方法,这种方法有点来回反弹的感觉,所以这实际上,希望很明显,如果你选择β\beta 等于零,那么这个项就等于梯度,所以 β\beta 等于零就是梯度下降。β\beta 等于一则没有任何作用,因为梯度中有线性因子,所以 β\beta 必须小于一。

通常来说,有一些疯狂的方法实际上使用了大于一的 β\beta ,但这是没有意义的,但有时候人们可以在合适的权重下使用这些方法。你肯定不能完全用 β\beta 大于一来进行这个更新,但有时候可以进行一些修改的更新,关键是 bβ\beta 等于零显然是梯度下降,你可以看到,梯度下降会像之前看到的那样反复弹跳。

但如果我们选择 β\beta 等于0.7,我们可以看到开始平滑地对这些项进行平均,并最终收敛,所以这是一个基本思路。现在,你可能注意到我们实际上,因为我们有很多东西,我们有一些历史上动量积累的情况,我们经常超过最优点等等,但这只是一些效果。在实践中,动量是一种非常常见的方法。

"Unbiasing" momentum terms

好的,你可能注意到动量有一种有趣的效果,那就是在早期的迭代中,utu_t比梯度小,对吧?因为,例如,我们常常会将动量项初始化为零,所以你会得到像u0=0u_0 = 0这样的表达式,然后你有u1=βu0u_1 = \beta u_0,但那只是零,所以这个项并不起作用,然后乘以1β1 - \beta倍的初始参数的梯度,对吧?

再次强调,我们马上就要讨论初始化,但是这个θ0\theta_0就是你如何初始化θ\theta的,你在这里注意到的是,这个值比梯度要小,它在某种程度上对梯度进行了缩放,使得第一次的梯度步长变小。如果你记得前面的幻灯片,第一次的梯度步长会向这个方向前进,但是第一次的动量步长只会前进一小步,因为它还在热身,动量项还在热身,对吧?

在我们使用动量方法优化参数时,我们通常会在初期遇到一个问题:动量项的大小比梯度要小。为什么会这样呢?这是因为我们通常将动量项初始化为零,而且在早期的迭代中,动量项的增长相对较慢。

有时候,你可能并不希望动量项这么小,你可能希望它能够更快地逼近梯度的大小。幸运的是,我们可以通过在动量项上施加一个缩放因子来解决这个问题。这个缩放因子的作用是校正动量项,让它的大小更接近于梯度的大小,这就是biased momentum

具体来说,我们之前的参数更新是用θtα\theta_t - \alpha乘以动量项,现在我们要做的是将动量项除以1βt+11 - \beta^{t+1}。在此,β\beta是我们设置的动量系数,tt是迭代次数。注意这里的t+1t+1实际上是指数,不是下标。通过这个操作,我们就对动量项进行了校正。

这个校正的好处是,动量项的大小在每一步都接近于梯度,使得我们在每次迭代时都能取得相似的步长。也就是说,你不再会在早期的迭代中走小步,而是能走出比较大的步伐。

这种方法有可能使我们的优化算法收敛得更快,因为它在某种程度上避免了早期迭代中由于动量项过小而导致的慢速前进。但这并不总是个好主意。有时候,你可能希望在开始时走小步,因为你还没有一个好的方向估计,你可能想要慢慢探索。这个选择是根据你的需求和问题的具体情况来决定的。

Nesterov momentum

我还想在这里补充一种在深度学习中有时会用到的动量类型,那就是Nesterov动量。因为各种原因,Nesterov动量实际上是一个非常有用的工具,无论是在实际应用中还是作为理论工具。我必须承认,有很多,我可能无法全部介绍,但是有很多技巧被人们用来加速梯度下降和其他类似的事情,以使梯度下降收敛得更快。我们不会讲解所有这些,我们将讲解最常用于深度学习的一些,其中之一就是动量,另一个常见的就是Nesterov动量

所以,Nesterov动量的作用是实际上对我们的正常动量更新进行了微小的调整,这被认为是一个非常好的主意。它的做法是,取我们的正常动量更新,也就是 1β1 - \beta 乘以时刻 tt 的梯度,但不是简单地在当前点处计算梯度,而是基于我们当前的动量项,我们实际上会走出我们将要走的步伐,评估那里的梯度,然后基于那个项进行更新。

我知道这看起来有点奇怪,但我实际上并不想深入讨论,然后我们的梯度更新是相同的,所以是 tαutt - \alpha u_{t}. 当然,你也可以为所有这些事情做偏差修正,那也是可以的。这似乎有点奇怪,不清楚这为什么是正确的做法,但我要说的是,对于某些凸优化问题,事实证明这实际上是一个非常好的主意。出于一些技术原因,你可以得到更好的收敛,你可以证明对于这种更新,你可以得到比正常梯度下降更好的收敛速率,所以这是一种好的事情。我在这里提到这个不是因为我们真的关心收敛性,再次强调,就像牛顿法一样,这些在我们处理深度学习中的非凸优化问题时能扩展多少,这有些不清楚,但这是一种很好的技巧,你可以在某种程度上预计的点计算梯度,这通常是一个好主意。

好的,所以这就是Nesterov动量的基本思想,它可以以几种不同的方式实施,有一些稍微不同的版本,但Nesterov动量的核心思想就是你在评估梯度时,并非完全在当前迭代,而是在一些更新的点,所以有点像在你形成你的最终更新之前的半小更新的点。好的,实际上,在这种情况下,它收敛得相当平滑,对,所以你可以得到那种很好的收敛模式,事实上,对于你的动量值相同的情况,它收敛得更快,它有一种更平滑的轨迹,收敛得很好。