AdaHessian在去往最低限度的路上。(图片由作者提供)
深度学习中使用的大多数优化器都是(随机的)梯度下降法。他们只考虑损失函数的梯度。相比之下,二阶方法也考虑到了损失函数的曲率。有了它,可以计算出更好的更新步骤(至少在理论上)。目前只有少数二阶方法可用于深度学习--其中之一是2020年由Yao等人发表的AdaHessian,作者提供了一个PyTorch实现。
在其最基本的形式中,二阶方法需要计算Hessian矩阵,它包含N×N个元素,其中N是神经网络中的参数(权重)数量。这对大多数模型来说是不可行的。AdaHessian包含一些有趣的技术来解决这个问题。然而,它们乍看之下可能很复杂。本文将介绍这些有效计算Hessian矩阵的近似值的技术。
动机
梯度下降法只用损失函数的一阶导数来建立模型:算法在负梯度方向迈出足够小的一步(由学习率控制),从而使损失值下降。损失函数的曲率信息(收集在Hessian矩阵中的二阶导数)被忽略了。
图1显示了当前位置的损失函数(绿色)和梯度(红色)。左图显示了梯度与损失函数局部完全匹配的情况。右图显示了在向负梯度方向移动时损失函数转为向上的情况。虽然在左图中应用一个大的更新步长可能是有意义的,但在右图中需要一个较小的更新步长,以避免对最小值的过度处理。
图1:损失函数f(w)(绿色)和它在w=-1的梯度(红色)。(图片由作者提供)
牛顿更新步骤
牛顿的方法正是处理这个问题:它同时考虑到当前位置的梯度和曲率。它对损失函数f(w)(用w表示模型的参数或权重)用二次模型进行局部建模。更新步骤如下(公式见图2)。
- 使用泰勒多项式计算出一个二次模型m
- g是梯度,H是Hessian矩阵。
- 为了找到该模型m的最小值,计算该模型的导数,将其设为零,并求解更新步骤Δw
- 这就给出了牛顿更新的负梯度,并通过Hessian的倒数进行了旋转。
图2:推导出牛顿方法的更新步骤。(图片由作者提供)
梯度和Hessian都可以通过PyTorch这样的深度学习框架来计算,这就是应用牛顿方法所需要的一切。然而,对于一个有N个参数的神经网络模型,Hessian矩阵由N×N个元素组成,这对于典型的模型来说是不可行的。AdaHessian用一个对角线矩阵来逼近Hessian矩阵,该矩阵仅由N个元素组成(与梯度向量大小相同)。
计算Hessian的对角线
我们现在有了牛顿更新公式,我们把Hessian的近似限制为对角线矩阵。让我们看看它是如何计算的。
哈钦森的方法
图3显示了Hutchinson方法的公式,它计算Hessian的对角线元素。
- 通过投掷硬币创建一个随机向量z,并设置+1为头,-1为尾,所以在二维情况下,z可以是(1,-1),作为一个例子
- 计算矩阵-向量积H-z
- 用上一步的结果z⊙(H-z)与z的元素相乘(用⊙表示)。
- 计算期望值(或在实际执行中使用z向量的多个实例的平均值)。
图3:哈钦森计算H的对角线的方法(图片由作者提供
乍一看,这很奇怪。我们已经需要H来获得H的对角线元素--这听起来不是很聪明。但事实证明,我们只需要知道H-z(一个矢量)的结果,这很容易计算,所以我们从来不需要知道整个Hessian矩阵的实际元素。
但是哈钦森的方法是如何工作的呢?当把它写在二维情况下(图4),就很容易看出。元素相乘指的是将向量逐行相乘。检查z⊙(H-z)的结果,可以看到其中有z₁²(和z₂²)的项和有z₁-z₂的项。当计算z⊙(H-z)的多次试验时,z₁²(和z₂²)总是+1,而z₁-z₂在50%的试验中给出+1,在另外50%的试验中给出-1(简单写出所有可能的产物。1·1, 1·(-1), (-1)·1, (-1)·(-1)).当计算多次试验的平均值时,包含z₁-z₂的项趋于零,我们剩下的就是H的对角线元素的向量。
图4:二维情况下的哈钦森方法。(图片由作者提供)
矩阵矢量乘积
现在只剩下一个问题了:我们没有哈钦森方法中使用的Hessian矩阵H。然而,正如已经提到的,我们实际上不需要Hessian。如果我们有H-z的结果就足够了。它是在PyTorch的自动微分功能的帮助下计算出来的:如果我们把PyTorch已经计算出来的梯度,乘以z,然后对参数向量w进行微分,我们得到的结果与我们直接计算H-z的结果相同。因此,我们可以在不知道H的元素的情况下计算H-z。图5显示了为什么这是真的:再微分一次梯度就可以得到Hessian,而z被视为一个常数。
图5:我们用PyTorch的自动微分功能计算的结果(左)和我们在哈钦森方法中需要的矩阵向量积H-z(右)是相等的。(图片由作者提供)
把它放在一起
我们现在有了梯度和Hessian的对角线值,所以我们可以直接应用牛顿更新步骤。然而,AdaHessian采用了与Adam优化器类似的方法:它对多个时间步骤进行平均,以获得更平滑的梯度和Hessian的估计。
一个单一的更新步骤看起来如下。
- 计算当前梯度
- 计算当前对角线Hessian的近似值
- 将梯度与先前的值混合起来进行平均
- 将Hessian与先前的值混合后进行平均,并注意对角线元素是正的(否则,我们最终可能会向上升方向移动)。
- 计算牛顿更新步骤,包括一个学习率参数,以避免步骤过大导致发散。
在图6中,一个简单的二次函数通过梯度下降和AdaHessian进行了最小化。这里,AdaHessian的使用没有动量。在这个玩具例子中,与梯度下降法相比,它收敛得更快,而且不需要调整学习率。当然,最小化二次函数倾向于二阶优化器。
图6:实现二次函数最小化的三个步骤。左图:梯度下降法与适当的学习率。右边。使用对角线Hessian近似的牛顿方法(右)。(图片由作者提供)
结论
AdaHessian通过(1)使用对角线近似,(2)利用Hutchinson方法和(3)PyTorch中的自动微分功能,解决了计算Hessian的任务。
链接。
AdaHessian:深度学习的二阶优化器》最初发表于Towards Data Scienceon Medium,人们通过强调和回应这个故事来继续对话。