最近系统学习了神经网络训练中常见的 gradient descent 系列优化算法, 现将学习笔记整理如下, 主要包括:
深度学习与单纯的最优化有何不同
基础的 graident descent 算法
基于 momentum 的改进算法
基于 adaptive learning rate 的改进算法
总结
1. 深度学习与单纯的优化有何不同
深度学习可以简单理解为减小 (优化) 损失函数的过程, 这与单纯的最优化一个函数十分相似, 但深度学习并不是单纯的最优化, 主要区别是目标不同. 深度学习的目标是模型在测试集上的 performance, 也就是减小泛化误差. 而训练过程中我们只可以利用训练集, 因此深度学习的优化目标是间接的. 对于单纯的最优化而言, 优化目标往往是直接的, 例如, 如果将优化目标定为最小化训练集上的损失函数, 则深度学习在训练集上的训练过程, 就可以视为单纯的最优化过程.
2. 基础的 gradient descent 算法
根据一次迭代 (更新一次模型参数) 所使用的数据量, 可以分为 Batch gradient descent(BGD), Stochastic gradient descent(SGD)和 Mini-batch gradient descent(MBGD).BGD 一次迭代使用整个训练集的数据, SGD 一次迭代使用 1 个训练样本, MBGD 是前两种方法的 trade-off, 一次使用一小批样本(如 32,64,128 等). 其更新公式可以统一描述如下:
x += -learning_rate * dx
x 为模型参数, dx 为 x 的梯度大小. 三种算法的区别在于计算 dx 所使用的训练样本数目.
BGD 方法因为使用整个训练集计算梯度, 得到的梯度是损失函数在该位置真实的梯度, 所以能够保证收敛到全局最优点 (凸函数) 或局部最优点(非凸函数). 缺点是时间和空间复杂度较高, 因为 BGD 计算所有训练样本才能更新一次模型参数, 更新依次模型参数需要花费更多的时间. 同时如果利用向量化的方式实现 BGD, 需要缓存整个训练样本集, 对于大规模训练集也难以实现.
SGD 方法利用单个样本的梯度估计整个训练接的梯度, 得到的梯度具有较高的误差, 因此利用该梯度更新模型参数不一定会使得损失函数减小, 往往随着迭代的过程, 损失函数会出现波动的现象, 并且 SGD 最终也难以在局部最优点附近停止, 而是在其周围震荡, 如果随着迭代减小 learning_rate,SGD 也可以同 BGD 一样收敛到最优点. SGD 虽然更新模型参数的频率更快, 但是更新参数使用的梯度带有较高的噪声.
MBGD 方法是介于前面两种方法之间, 每次从训练集中随机抽取一小批训练样本, 用于计算梯度完成一次模型参数更新, 相比于 BGD,MBGD 方法迭代频率更高, 训练速度更快. 相比于 SGD, 迭代使用的梯度更加准确, 训练过程更加稳健, 利用向量化实现过程也可以实现较快的运算.
上述三种方法中, Mini-batch gradient descent 是目前最常采用的训练方式, 一般提到的 SGD 也代指的是 MBGD 方法, Mini-batch 的训练方式也是后续 momentum gd 等改进方法的训练模式.
基础的 gradient descent 方法具有一些共有的弱点, 主要包括:
learning_rate 选择的问题, 基础的 gd 方法需要人工设置合适的超参数 learning_rate, 学习率过小会使得训练非常缓慢, 学习率过大会导致训练难以收敛甚至发散.
learning_rate 对于每个维度的特征都是相同的, 但是对于不同出现频率的特征或者曲率相差很大的特征(损失函数的 Hessian 矩阵病态, 特征值大小相差很大), 我们往往希望它们具有不同的学习率.
无法逃逸大量存在的鞍点的问题.(大型神经网络中收敛到一个不错的局部最优点也是可以接受的, 真正带来麻烦的是大量存在的鞍点, 而鞍点周围往往存在梯度很小的平原, 该问题会在总结部分进行展开论述).
针对基础的 gd 存在的上述挑战, 大牛们对 gd 算法进行了魔改, 主要有两条线路, 改进发展如下图, 下面两节分别介绍两类改进方法.
3. 基于 momentum 的改进算法
3.1 指数加权滑动平均方法
两类改进基础 gradient descent 的方法都使用了指数加权滑动平均的方法, 相比于算数平均运算, 该方法时间复杂度和空间复杂度都有较大优势. 定义如下:
\[v_t = \beta v_{t-1}+(1-\beta)\theta_t\]
其中,\(\theta_t\)为指数加权平均的数据,\(v_t\)为指数加权平均的结果,\(\beta\)为指数加权参数, 一般设置 \(v_0=0\).
\(\frac{1}{1-\beta}\)近似为指数加权平均的数据个数, 例如,\(\beta=0.9\), 则 \(v_{20}\)则代表这 \(\theta_{20}\)到 \(\theta_{11}\)的指数加权平均结果, 在 \(\theta_{11}\)之前的数据也对结果有影响, 但影响十分有限, 可以忽略.
上面迭代求解的过程, 在运算初期会有明显的偏差, 纠正方法是令 \(v_t = \frac{v_t}{1-\beta^t}\)
3.2 momentum 算法
momentum 算法的更新公式如下:
- v = mu*v - learning_rate * dx
- x += v
其中, v 是指数加权滑动平均累加量(该公式与 2.2 节计算公式形式不同, 但指数加权滑动平均的思想一致),mu 是 momentum 引入的超参数(一般设置为 0.9).
momentum 算法可以借用物理概念很好的理解, 想象一个小球从山顶滚落, mu*v 这一项相等于速度项(忽略其符号), 后面一项相当于加速度项, 小球在滚落过程中, 不仅受到当前时刻的加速度影响, 而且收到积累起来的速度影响(momentum 相较于基础 gd 多出来的部分), 类似于加了惯性作用, 而 mu 参数是一个 decay 参数, 类似与摩擦力的作用, 随着迭代进行, 时间久远的累加值起到的作用将越来越微弱.
当特征间曲率差异大时, 基础的 GD 方法会产生 zigzag 现象, 会在曲率大的方向上有较大的震荡, 而曲率小的方向上前进较慢, momentum 算法可以有效抑制这种现象. 训练对比图像如下所示(图片来自 "花书")
图中椭圆为损失函数等高线, 显然 45° 方向上特征具有更大的曲率. 红色实线为 momentum 训练过程, 黑丝箭头表示基础 GD 在该位置将要迭代的位置. 比较可见 momentum 有效减小了训练过程中曲率较大方向上的震荡, 增加了曲率较小方向上的迭代步长. 这是因为在指数加权滑动平均的过程中, 曲率较大方向上的梯度由于正负交替出现, 进行了抵消, 而曲率较小方向上的梯度符号一致, 累加的过程中增大了梯度, 等效于增加了迭代步长.
momentum 方法使得训练过程带有惯性, 好的方面是可能便于训练逃逸损失函数的鞍点或者平坦区域, 不好的方面是在到达最低点时, 由于带有惯性不能立刻停止, 会发生 overshoot 最低点的现象.
3.3 Nesterov momentum 算法
前面提到 Momentum 算法在最低点会发生 overshoot 现象, 能不能在快到底最低点前减小梯度, 就能减弱该现象, Nesterov momentum 正式基于这个考虑改进 momentum 算法的. 其更新公式如下:
- \[v_{
- t
- } = \mu v_{
- t-1
- } - \alpha \nabla(\theta_{
- t-1
- }+\mu v_{
- t-1
- })\]
- \[\theta_t = \theta_{
- t-1
- } + v_t\]
比较 momentum 算法可见, 唯一的区别是计算梯度部分, Nesterov 相较于 momentum 计算的是参数 \(\theta_{t-1}\)更新 \(\mu v_{t-1}\)之后的梯度. Nesterov 的思想是既然我们已经知道了参数 \(\theta_t\)要更新 \(\mu v_{t-1}\)这一部分, 为什么不先用 \(\mu v_{t-1}\)更新参数, 然后在计算梯度呢, 这样用 \(\theta_{t-1}+\mu v_{t-1}\)近似模拟了 \(\theta_t\), 起到了前瞻梯度的效果. 至于 Nesterov 为什么要比 momentum 效果好, 而已这样理解, 当前瞻到的梯度比当前梯度大时, 这一步更新的梯度会更大, 反之, 当前瞻到的梯度比当前梯度小时, 这一步更新的梯度会更小.
例如小球从山顶向山底滚落, 开始阶段, 当山坡的斜率越来越大时, 由于前瞻到的梯度比当前梯度要大, 所以更新步幅越来越大, 可以加快训练. 当小球接近山底时, 山坡梯度越来越小, 则更新歩幅会提前缩小, 可以见减小 overshoot 现象.
4. 基于 adaptive learning rate 的改进算法
前面介绍了基于 momentum 的改进算法, 这一类改进算法能够加速 gd 的收敛过程, 并且对于不同曲率的特征起到了很好的平衡效果. 本节主要介绍给予自适应学习速率的改进方法, 这一类方法能够自适应地赋予不同频率 (泛指的) 的特征以不同的学习速率.
4.1 Adagrad 算法
Adagrad 算法是这一类改进算法的鼻祖, 更新公式如下:
- cache += dx**2
- x += -learning_rate * dx / np.sqrt(cache + 1e-7)
Adagrad 算法对各个参数的梯度平方进行了累加, 并将当前的梯度用累加值进行了加权, 可以发现某个参数的梯度较大, 则其累加和比较大, 则最终更新参数时其权重越低, 也就是学习率越小. 而某个参数的梯度较小, 则其累加和也比较小, 则其学习率衰减的比较慢.
为什么说 Adagrad 对不同出现频率的特征具有赋予不同的学习率, 个人理解是, 不同维度的特征可以理解为不同参数的梯度 (有很大的欠妥, 但根据求导法则, 特征往往是模型参数梯度的重要影响因素, 例如 \(z = \theta_1x1+\theta_2x2\), 参数 \(\theta_1,\theta_2\) 的梯度分别为 x1 和 x2), 则某些维度的特征出现频率很低, 则其累加值会比较小, 则其学习率就相对更大.
Adagrad 算法具有非常明显的弱点, 那就是梯度平方的累加会越大越大, 各个参数的学习率会被衰减的越来越小, 导致后期训练越来越慢, 可能难以到达最优点. 后面的方法针对这一点进行了改进.
4.2 RMSProp 算法
RMSProp 算法不是公开发表论文中的算法, 而是大牛 Geoff Hinton 在一次授课中提出的算法, 主要思想是将指数加权滑动平均思想引入了 Adagrad 算法, 更新公式如下:
- cache = decay_rate * cache + (1 - decay_rate) * dx**2
- x += -learning_rate * dx / np.sqrt(cache + 1e-7)
指数加权滑动平均思想的引入, 使得 cache 发生指数衰减, 缓解了 Adagrad 后期学习率衰减过小的问题. decay_rate 是 RMSProp 算法引入的超参数, 一般设置为 0.9.
4.3 Adadelta 算法
Adadelta 算法相较于 RMSProp 算法, 用另外一个指数加权平均替换掉了全局 learning_rate, 其更新公式如下:
- cache = decay_rate1 * cache + (1 - decay_rate1) * dx**2
- dx^ = dx * np.sqrt(delta + 1e-7) / np.sqrt(cache + 1e-7)
- x += - dx^
- delta = decay_rate2 * delta + (1-decay_rate2) * dx^ ** 2
Adadelta 缓存了模型参数更新平方的指数加权平均, 作为自适应的全局 learning_rate, 因此我们完全不需要人为设置一个全局学习率了.
4.4 Adam 算法
Adam 算法结合了 momentum 和 RMSProp 两种算法, 并添加了指数加权滑动平均的偏差矫正, 其更新公式如下:
- m = beta1 * m + (1 - beta1) * dx
- v = beta2 * v + (1 - beta2) * dx**2
- m /= 1 - beta1**t
- v /= 1 - beta2**t
- x += -learning_rate * m / (np.sqrt(v) + 1e-7)
其中参数 t 是迭代次数, beta1,beta2 是 Adam 算法引入的超参数, beta1,beta2 的默认值为 0.9 和 0.999.
5. 总结
本篇笔记总结了深度学习中常见的优化算法, 主要包括基础的 Gradient descend 算法和两类改进算法, 其中 Adam 算法是两类改进算法的集大成者, 兼具 momentum 系列算法和 adaptive learning rate 算法的优点, 是受到普遍推荐的算法. 实际应用中, 据说基础的 gd 方法往往能够达到更低的 loss, 所以有前段使用 Adam 算法加速训练, 后期采用基础 gd 收敛到更低点的做法.
上述内容之外, 还有三个额外的内容.
5.1 关于优化方法的可视化
本部分的动图来源于 Sebastian Ruder 的综述文章, 可以形象的对比各个不同算法的性能. 图中 NAG 算法代指 Nesterov momemtum 算法.
5.2 关于深度学习中局部最优和鞍点的问题
在之前神经网络的优化过程中, 人们非常担心陷入局部最优, 而无法找到全局最优的问题, 而在深度神经网络中, 我们更为关心的是优化算法逃逸鞍点的问题, 为什么会这样呢? 主要是基于两点考虑(理解自花书):
对于深度神经网络而言, 鞍点的数量远大于局部最优点的数量(遇到鞍点的额概率高得多), 这是因为局部最优点要求损失函数特征值全部大于 0(正定的), 也就是所有特征的曲率都是大于 0 的, 这对于高维空间而言出现的概率远低于鞍点(鞍点要求曲率有正有负). 类似与抛出大量的硬币, 要求硬币都是同一面朝上的概率要低很多.
对于深度神经网络而言, 找到一个局部最优点是可以接受的, 因为大型神经网络中的局部最优点也具有很小的损失函数.
5.3 关于选择 learning_rate 的问题
learning_rate 选择的问题其实也属于超参数训练的范畴, 实践中是需要根据不同的任务和训练样本进行调试的, 对于基础的 gd 方法, 基于 momentum 的改进方法, 往往需要 decay learning_rate, 使得训练初期速度较快, 而后期能够收敛到最低点. 对于 adaptive learning rate 算法, 理论上只需要设置一个全局 learning_rate 就可以, 算法本身带有学习率调整策略.
参考内容:
- Deep Learning(花书, Ian Goodfellow and Yoshua Bengio and Aaron Courville)
- An overview of gradient descent optimizationalgorithms https://arxiv.org/pdf/1609.04747.pdf
- CS231n Convolutional Neural Networks for Visual Recognition https://cs231n.github.io/neural-networks-3/#update
来源: https://www.cnblogs.com/hello-ai/p/12330614.html