雷锋网 AI 科技评论按:继在《要做好深度学习任务,不妨先在损失函数上「做好文章」》一文中为大家深入浅出地介绍了损失函数的相关知识后,Deep Learning Demystified 编辑、数据科学家 Harsha Bommana 本次接着从优化的角度,结合数学方式和可视化图,带大家以「看得见」的方式来了解神经网络如何一步步找到最小化的损失值,并最终实现最优化。
在前一篇文章《要做好深度学习任务,不妨先在损失函数上「做好文章」》中,我们对损失函数有了一个比较清晰的认知,它能够让我们知道模型在某一阶段的表现情况。现在,我们需要使用损失函数来训练网络以提高网络的性能。根本上,我们需要做的其实是获得损失值并尽可能地将其最小化,因为损失值越小,模型的性能就越高。最小化数学表示的这一过程就叫做优化,下面我们就看看如何在神经网络上将这些优化方法用其起来~
在神经网络中,每个层之间都有很多权重。我们需要了解的是:神经网络中每层的每个权重都会以某种方式影响到网络的输出,这是因为它们全都直接或间接地与输出有关联。
因此,我们可以说,如果我们改变神经网络中的任一特定的权重,网络的输出也会改变。
如下图所示,我们尝试了 3 种不同的场景。在每个场景中,我们都选择了一些随机的权重,并对其进行了更改。同时,下图也显示了,改变选择好的权重会对神经网络的哪些部分产生影响以及哪些部分不构成影响。在这 3 个场景中,网络的最后一层都至少有一个受影响的节点。由于最后一层的所有节点都与输出节点相连,所以我们可以说,只要最后这层的部分某部分受到权重变化的影响,那输出节点也同样会受到影响。
网络更改特定权重会对网络的哪些部分产生影响的可视化图
从上图中,我们同样可以观察到,权重离输出节点更远(离网络的始端更近),会更多地影响到网络始端和输出节点之间的节点。因而,我们可以判断,权重对输出的影响是非常间接的,因为在这些权重和输出之间还存在很多权重。离输出节点更近的权重则会更少地影响到网络始端和输出节点之间的节点,因此它们会更加直接地影响到输出节点。
了解如何通过改变权重来改变网络的输出后,我们接下来要知道如何最小化损失。改变权重就会改变输出,而改变输出就会改变损失——因为损失就是一个预测 (Y_pred) 值的函数,而这个值本质上就是网络的输出。所以,我们可以得出的结论是,改变权重最终会让损失也发生改变。
我们已经展示了权重和最终的损失之间的关系,但是目前为止我们还仅仅探讨了改变。改变可以是增加的意思,也可以是减少的意思,而在这里我们需要的是减少损失。所以,我们需要探索以这种方式来改变权重究竟如何能够能让损失减少。这一过程就叫做优化。
从数学的角度来看,我们可以通过使用偏导数(Partial Derivatives)来实现这个过程。偏导数能够让我们理解两个数学表达式如何相互影响。让我们先假设 X 和 Y,它们之间存在某些任意的数学关系,如果我们能够得到 X 对 Y 的偏导数,我们就能够知道 X 的改变如何影响 Y。如果偏导数为正,就意味着 Y 会随着 X 的增大而增大;如果为负,则意味着 Y 随 X 的增大而减小。
如此一来,我们需要得到神经网络中的每个权重对损失的偏导数。在某个特定案例中,如果权重的偏导数为正,那我们就减小权重从而减小损失;如果为负,我们就增大权重以减小损失——毕竟优化最终的目标就是:减小损失!
优化损失的偏导数可视化图
对应用到的算法就是梯度下降(Gradient Descent)算法,它又名随机梯度下降(Stochastic Gradient Descent,SGD),是神经网络优化中最基础的算法。这一算法执行的是一个迭代过程,所以我们要多次更新每个权重的值,直到损失收敛为一个合适的值。我们不妨将单轮更新用以下数学公式来表示:
在这里,alpha 符号表示学习率(Learning Rate),它对神经网络的优化速度有影响。如果学习率较大,我们就能更快地给损失找到一个最小值,因为每次更新的权重跨度够大,不过,从最终的值来看,我们或许无法找到一个很好的最小值,这是由于每次更新的权重跨度太大,就有很能会直接跨过这个很好的最小值。而采用更小的学习率则能够解决这一问题,不过这就需要花很多步来让神经网络的损失减小到一个不错的值。所以,我们需要让学习率维持为一个最佳值,一般而言,0.01 是 alpha 的一个比较安全的取值。
然而仅仅使用梯度下降算法存在的一个大问题是,如下图所示,损失无法趋近于全局最小值,而仅能不断接近局部最小值。
SGD 局部最小值问题
我们从标记的绿点看起,第一个绿点之后的每个绿点都表示依次更新后的新权重和损失。由于偏导数(梯度)在无限接近局部最小值时基本上等于 0,因此梯度下降仅仅在找到局部最小值之前发生。所以,在求到局部最小值后,梯度下降基本上就会原封不动,并不会继续尝试去找到全局最小值。
上图非常简单,而在现实中,这张图要复杂得多,存在很多个局部最小值,所以如果仅仅使用梯度下降算法,并不能确保能够找到一个不错的损失。针对这一问题,我们可以采用动量的方法。
在动量中,我们需要做的基本上就是获取权重在本次更新之前经过的所有更新的一些信息。根本上而言,如果权重持续往一个特定方向变化(增大或减小),它就会慢慢地积累下该方向的「动量」。因此,当权重遇到一些抵抗力并最终往相反的方向变化时,由于此前积累的动量,它就能够继续按原来的方向变化。
这与物理中的实际动量类似。我们想象有一个走廊和一个球,当我们在走廊的一遍发球时,它会持续滚动一段时间,在此过程中,它就为往该方向的前进获取的动量。最后,当球滚动到底时,也不会就停在那里,而是往相反的方向再滚动一会,这是因为它在此之前所获得的动量——即便重力会让它停下来,然而动量会让它继续滚动一会。
我们尝试从数学的角度来再现这一场景,以便让梯度下降算法能够在经过局部最小值后继续尝试取得全局最小值,公式如下:
动量算法的权重更新公式
权重更新公式(动量)
这里的 V 表示的是动量因子(Momentum Factor),如公式所示,在每次更新中,它都会将前一次更新的动量因子加到当前导数上。之后,我们仅需要将这个值加上权重,即可得出更新后的权重。其中 n 在这里指的是动量系数(Coefficient of Momentum),它决定权重每次往前移动所获得的动量为多少。
当权重更新后,权重也会在动量因子中将所有此前的梯度存储为一个部分。这样的话,一旦权重需要往相反的方向变化,例如达到局部最小值时,它依旧会朝同一个方向变化一段时间,直到动量因子的数量逐渐减少,才往相反的方向变化。在多数情况下,动量因子通常都足以让权重解决到了局部最小值便停止的问题。
动量可视化示例
动量算法的另一个附加优势是:由于梯度的积累,权重会更快地收敛成一个合适的损失值。优化中还有哪些能够让梯度下降以更精准的方式执行的技术呢?我们下面来看。
涅斯捷罗夫梯度加速(Nesterov accelerated gradient,NAG)
在 NAG 中,我们要做的不是计算当前位置的梯度,而是计算与当前位置接近的未来位置的梯度。这样做的原因是我们希望以一种更加精准的方式来计算梯度。动量在取得最小值前就会开始减小,因为其使用的梯度是未来位置的梯度。这种方法结果会提高收敛期间的稳定性并减少波动,进一步,它在实际应用中的表现也比单纯用动量算法更好。
接下来我们来看具体如何在神经网络权重的优化中使用 NAG。
扩展后的整个动量方程式如下:
扩展后的动量全方程式
这里的下一个权重值 W 由「n*v_old」和「alpha *当前梯度」以及当前权重相加得出。假设「alpha *当前梯度」的值变得很小,我们就能通过仅将「n*v_old」与当前权重值相加来趋近于下一个 W 值。
计算趋近于未来位置的权重值
现在,我们要计算的不是当前 W 值的梯度,而是未来 W 值的梯度。这就让动量因子在真正面临剧烈的梯度变化前提前适应,从而其训练期间的稳定性得以提高。
涅斯捷罗夫动量公式
这个带有 NAG 的新的动量方程式显示,我们采用的是趋近于未来位置的 W 值的梯度而不是当前位置的 W 值的梯度。
涅斯捷罗夫可视化示例
如上面使用 NAG 方法的示例所示,我们给当前位置的 W 值加上了「n*v_old」以趋近于未来位置的 W 值。然后,我们计算未来位置的梯度值,并在计算「v_new」值时使用该值而非当前位置的梯度值。在本示例中,虽然在该场景中,动量在理论上应该是增加的,然而它在经过该位置时就开始减小了,这是因为未来位置的 W 值的梯度是指向相反方向的,所以动量值不增反减。
下面我们来看一些自适应优化方法。
在自适应优化方法中,学习率(alpha)和动量系数(n)在整个训练过程中都不再是连续的,而是连续地适应网络中的各个权重,因而会随权重一同变化。这些类型的优化算法都属于自适应优化这类方法。
第一个要介绍的自适应优化算法是 Adagrad 算法。
Adagrad
涅斯捷罗夫是自适应梯度算法的简称。在该算法中,我们需要为权重的每轮更新更改学习率(alpha),它们在每轮更新期间的更改方式为:如果权重在较短时间内被更新的太多次,它就会减小;反之增大。
首先,每个权重都有自身的缓存(Cache)值,新的缓存值由自身原本的缓存值加上其在当前位置前的梯度的平方得出。
Adagrad 的缓存更新值
在训练过程中,该缓存值会持续增大,新的权重更新公式如下所示:
Adagrad 权重更新公式
除了学习率(alpha)在整个训练过程中会持续变化外,该公式与原本的梯度下降公式一样。公式分母中的 E 是一个非常小的值,它是为了确保该公式不会出现「分子除以零」的情况。
具体而言,在该公式中,如果权重的更新非常大,缓存值就会增大,结果会导致学习率变小,从而让权重的更新幅度持续减小。另一方面,如果权重并没有发生较为明显的更新,缓存值就会变得很小,结果会让学习率增大,进而会增大权重的更新幅度。这就是 Adagrad 优化器的基本原理。
然而,该算法的缺点就是,无论权重过去的梯度为多少,缓存值总会增大些,这是因为公式中的平方结果是非负数。这样的话,每个权重的学习率最终都会减小至一个非常小的值,直到训练过程再也不会发生较明显的变化为止。
下一个要介绍的自适应优化器——RMSProp 则能够解决这一问题。
RMSProp
与 Adagrad 相比,RMSProp 唯一的不同点就在于它的缓存更新策略。RMSProp 的公式引入了一个新参数——衰减率(Decay Rate),即 gamma:
RMSProp 的缓存权重更新公式
这里的 gamma 值一般为 0.9 或 0.99,因此对于每轮更新而言,相比于 Adagrad,公式中相加的与梯度的平方会乘上非常低的比率。这就确保了学习率能够基于此前更新的权重,像在 Adagrad 算法中一样持续变化,但与此同时,该学习率不会衰减得很快,因而它的训练过程会持续更长的时间。
再接下来,我们要介绍的是 Adam 优化器,总体而言,它被广泛视作深度学习优化中最佳的优化器之一。
Adam
Adam 有点像 RMSProp 和动量(Momentum)方法的结合体。我们首先计算 m 值,它表示的是当前位置的动量:
Adam 动量权重更新公式
该公式与动量公式的唯一区别就是,当前梯度值乘以的不是学习率(alpha)而是 (1-Beta_1)。
下一步我们计算累积的缓存值,这跟 RMSProp 中的计算方法一样:
最后得到的权重更新公式如下:
Adam 权重更新公式
如上公式所示,我们通过计算动量值来累加梯度值,与此同时,我们可以通过利用缓存值来持续更改学习率。由于这两个特征,Adam 的性能一般会比本文提到的以外的所有优化器都更好,因而在训练神经网络方面,它也是被开发人员偏好使用的优化器。在 Adam 的相关论文中,推荐 (Beta_1) 的参数取值为 0.9、(Beta_2) 的参数取值为 0.99 、(epsilon)的参数取值为 1e-08。
在本文中,我提到了多数深度学习从业者在基本的深度学习任务中最常用的几个最重要的优化器,希望大家能够通过阅读本文有所收获!
注:作者在本文中使用的 a(Loss)/a(Wi) 符号,实际上表示的是 Wi 值的 a(Loss)/a(W)。