卷积神经网络一般力求能够做到 end to end 的训练, end to end 训练也是目前深度学习的主流. 训练中主要采用 Back Propagation 算法, 而 BP 算法是我们早就学过的梯度下降算法的一种实现. 因此, CNN 中的各种优化算法还是在梯度下降算法上面做手脚, 这篇文章的主要目的是总结和比较深度学习中各种常用的优化算法. 这这篇文章中不会涉及到怎么求(偏)导数, 我们假设已经得到了(偏)导数.
Stochastic Gradient Descent
基本的 SGD
原始的 SGD 方法在机器学习中经常被称为 Vanilla update, 这和我们在高中学习过的梯度下降算法没有什么区别, 都是先求(偏)导数, 然后, 以一定的学习速率, 利用该(偏)导数去更新要优化的参数.
|
Momentum Update
Momentum update 是一种加快收敛速度的方法(注意, 这里说的不是计算速度). 这个方法来自于物理中的启发. loss function 看做是一座山, 对于参数的初始化看做是在这个山坡上面随机放一个小球. 这个小球的初始速度为 0, 其相对于地面(或者更严格的说是山谷, 也是Loss Function 优化过程中的局部最优点)的势能为
U=mgh
, 其中,
m
是小球的质量,
g
是重力加速度, h 是小球的位置相对于山谷最低点的高度. 因为
m
和
g
都是常数, 因此, 势能正比与高度
h
. 优化过程看以看做是模拟这个小球在山坡上的状态. 小球来自于地球引力的受力为
F=mg
, 而这恰好是 Loss Function 的梯度. 另外一方面, 小球的整体受力为
F=ma,a≠g
, 因为其中还有摩擦力等其它因素.
|
这里的变量 mu
就是我们在各种深度学习框架中/论文中见到的 momentum. 一般设置为 0.9, 0.99 等. 然而, 把 mu
理解为摩擦(或者加上其它的因素)更好. mu
的作用是在小球在山坡上滚动的过程中来降低小球的动能. 否则, 如果没有这个因素, 那么, 小球永远不会停下来, 优化过程也永远不会停止.
Nesterov Momentum
Nesterov Momentum 是最近比较流行的一种与传统的momentum update稍有不同的方法, Nesterov Momentum 在凸优化中有较强的理论保证收敛, 并且,在实践中, Nesterov Momentum也比单纯的 Momentum 的效果要好. 核心思想是: 注意到 momentum 方法, 如果只看 mu * v
项, 那么, 当前的 x
进过 momentum 的作用会变成 x+ mu*v
. 因此, 可以把 x+ mu*v
这个位置看做是当前优化的一个”展望”位置, 所以, 可以在 x+ mu*v
求导, 而不是原始的 x
|
自适应优化算法
在优化的过程中, 如果学习率设置的过大, 那么, 小球就会在山谷之间跳来跳去, 无法到达最低点, 如果是非常缓慢地降低学习速率, 那么, 虽然小球跳来跳去的现象会有缓解, 但是, 效果不明显, 浪费了计算资源, 而如果快速降低学习速率, 那么, 小球可能会很快到达一个(不是那么好的)局部最优点, 而不能到达一个更好的局部最优点. 通常, 在实验中有下面三种方法:
Step decay 每隔几个epoch减少一次learning rate, 一般是每运行5个epoch左右把learning rate减少一半, 或者是每隔20个epoch减少为原来的1/10. 然而,具体的learning rate 的调整方法还是要看网络的设计和模型. 另外, 还有一种方法是, 在训练的过程中观察training error和validation error, 当validation error不再减小的时候, 减小learning rate.
Exponential decay 的数学描述是 α=α0e−kt , 其中 α0,k 是超参数, t 是迭代次数.
1/t decay 的数学描述是 α=α01+kt 其中 (α0,k ) 是超参数, t 是迭代次数.
PS: 我一般使用第一种方法.
逐个调整参数
上面讨论过的所有的方法都是所有的参数都使用相同的调整策略. 调整学习率的代价一般比较高, 因此, 有许多研究还是如何自动调学习率, 甚至是调整每一个需要优化的参数的学习率. 在这些方法中往往会引入更多的超参数, 但是, 这些方法对超参数的设置并不是那么敏感, 因此, 总会比上面讨论过的调整学习率的方法要好用.
AdaGrad
pass
|
cache
的大小和gradient的大小相同, 记录的是每个参数的梯度的平方和. 之后,cache
用来以 element-wise 的方式 normalize 参数的更新. 从上面的代码中可以看出, 梯度较高的权重的有效 learning rate 会减小, 相应的梯度较低的权重的有效 learning rate 会增大. 这里, 让我感到不解的是, sqrt
操作非常重要,如果没有 sqrt
操作, 该算法的效果非常差. eps
用来避免出现除 0 错误的,一般设置为
10−4
到
10−8
之间. (这种方法,在 CNN 中训练中极为常见, 比如在 batch normalization 中也是通过这种方法避免出现除 0 的错误). Adagrad 的缺点是,在深度学习中, 这种方法导致学习率的调整太激进, 因此常常过早结束了学习过程.
RMSProp
RMSProp是一个非常高效的算法, 但是目前并没有发表. Hinton 老爷子果然任性. RMSProp 对 AdaGrad 稍作改进, 是的算法不再像 AdaGrad 那么激进 它使用的是 moving average of squared gradients, 有关 moving average 的相关解释可以参考 batch normalization 的实现说明.
|
decay_rate
是超参数, 一般可以设置为
0.9,0.99,0.999
. 其中, x+=
操作和Adagrad完全相同, 但是, 变量cache
是leaky的,所以, RMSProp 仍然根据每个权重的gradient来调整learning rate.
Adam
Adam 是最近提出的一种算法, 该算法和(下面将要介绍的)带有momentum的RMSprop比较类似, 过程类似于:
|
该方法和 RMSProp 唯一的区别是 “smooth” 过程, 这里使用的是 m
来做 smooth 操作, 而不是使用原始的 gradient vector dx
. 论文中推荐的超参数为 eps=1e-6, bata1=0.9, beta2=0.999
, 在实践中, 推荐使用Adam方法. Adam 算法通常会比 RMSProp 算法效果好. 另外,也可以尝试 SGD+Nesterov Momentum. 完整的Adam算法中还包括 bias 的纠正机制, 这是因为,在刚开始的几个steps中,m
和 v
都要初始化, 并且在 warm up 之前他们都 biased at zero. 更多的细节可以参考论文原文.