梯度下降算法_分享一个各种梯度下降的交互动画演示

8ff44727ab75b526a252534d4bda281a.png

UC Berkeley 春季深度学习课程最后一节讲述随机梯度下降以及动量机制。我盗用课程里面的例子,制作了一系列交互动画,演示 SGD,动量机制,RMSProp 以及 Adam 。在制作这一系列交互动画的过程中,我发现 Jupyter Notebook 的插件ipywidgets 提供了非常便捷的制作交互式教学动画的方法。这种方法基本上可以做到多加一条语句,将一个普通的 Python 函数转化为用户可点击,交互操作的动画。如果有感兴趣的同学,大家可以一起加入进来,制作更多介绍深度学习各方面概念的交互动画。动画运行效果如下,

c5d56f5537947b8a002c4b2bd9252511.png
随机梯度下降,Adam 算法https://www.zhihu.com/video/1109019791142236160

这篇文章接下来的部分会展示不同的梯度下降算法,在不同参数组合时的表现。远离公式,通过最直观的方式,显示各种梯度下降算法的表现,以及相应参数选择的原则。网上已经有非常多详细的公式推导和介绍,比如 http://ruder.io/optimizing-gradient-descent/ 。这里不再搬砖。以交互的方式探索不同参数选择时各种梯度下降算法的表现,这可能是第一篇。

原始梯度下降 SGD

ca5ba1e6aa2c64bb83d378ce2379f31b.png
原始 SGD,学习率(Learning Rate 简称 lr) 过小的话,在有限步内很难走到极小值点。

05123dfe167c7e1ffa4ff65694adbec6.png
原始 SGD,学习率 lr 稍大,就会造成剧烈震荡。表现为训练过程中出现 NaN(Not a Number),或者训练误差随训练 Epoch 的增加而增加的情况。

39f75658588a3e7128c69e6634fe669c.png
学习率 lr 如果选取合适,SGD会成功到达极小值点。但想要选中比较合适的学习率,比较困难。这也是为什么大家都很喜欢用对学习率不敏感的梯度下降算法,比如 Adam。在这个例子中,虽然 SGD 初期会沿着最速下降方向(即梯度更大的方向)剧烈震荡,但最终很好的收敛到极小值附近。

带动量的 SGD

1fae0c8b7e8ab543de68af6c61a333cb.png
不加动量之前,学习率 lr=0.61 时,损失函数已经发散。加入动量之后,同样的学习率,系统却能正确找到极小值点。中等大小的动量,可以帮助系统免疫震荡。

ee7d69a386dd00dcacb23345a2144a35.png
同样大的学习率,继续增加动量 beta 到 0.81,则会引入新的震荡。https://distill.pub/ 上有篇研究动量机制的文章,清楚的说明动量会消除某些震荡,也会引入新的震荡。削弱的是小球滚下山坡时沿最速下降方向的震荡,引入的是小球在V形谷底附近因惯性导致的左右摇摆。

f5124dcba2e921d286acbe5c74e8c320.png
一般的做法是选择大的动量 (beta=0.9),和小的学习率 (此例子中 lr = 0.02),以使带动量的 SGD 快速稳定收敛。为了在给定步数内成功到达极小值点,我们在在原始的 SGD 中选择 lr=0.42。作为对比,这里加了动量之后的SGD的学习率(lr=0.02)要远小于原始SGD的lr。说明动量可以加速收敛。

适配学习率算法 Adagrad

68a46f89b8da395c233f5ba359fbc2af.png
Adagrad 需要比较大的学习率才能在给定步内走到极小值点。原因是Adagrad是适配学习率算法。它对频繁更新的权重使用小的学习率,对比较稀疏,更新较少的权重使用大的学习率。算法累积每个参数的历史梯度平方,将其作为学习率衰减因子。可以看到后期更新点基本重合,意味着更新缓慢。

RMSProp 算法

90a6786f4e31e7639aeb65d4c3d03160.png
RMSProp 算法集成了动量机制与 Adagrad 两种算法的优点。可以看到与 Adagrad 结果相比,RMSProp的更新点分布更加均匀,可以使用更小的学习率 (lr=0.15) 在给定步到达极小值点,学习率后期衰减不严重。另一方面,与单纯的带动量的SGD 比,它的更新曲线比较平滑,震荡较小。

Adam算法

普罗大众最喜欢的算法莫过于Adam 算法。如果动量可以看成是小球沿斜坡的滚动,那么Adam可以理解成带摩擦的铁球,在平地的滚动。

f776b4826b489c446d6151f9735fd5cf.png
使用 Adam 文章里推荐的默认参数,可以看到就算选择了非常大的学习率 (lr = 1),Adam 的更新轨迹也只是围绕极小值点附近做S形环绕,而不是像原始SGD,带动量的SGD或其他算法一样直接发散。与手动选好学习率的带动量的 SGD 相比,Adam 在极小值点附近表现出复杂的非单调行为。

f89afa49831c4645cb991a73f0ce4efc.png
减小第一个参数 mu,会缩小极小值附近S形曲线的环绕区域,使结果更接近极小值点。这可能是为什么很多文章或开源代码里会选择第一个参数 (mu=0.5),而不是文章推荐参数 mu=0.9。

be6bcd95302ec44001aa11ee8100b3e8.png
无论 lr 以及 第一个参数如何选择,减小第二个参数 nu, 总会使更新轨迹变得更加曲折。所以最好的选择是使用比较大的 nu (=0.99)。

85d24dccd0dfa14c64751199d98f8955.png
固定 mu 和 nu, 无论 lr 选 1 还是 0.35, 系统都能在有限步内走到极小值附近。Adam 表现出良好的特性,一方面对学习率不敏感,另一方面非常稳定。

总结:

在日常读文章和读代码的过程中,最经常看到 Adam,RMSProp 以及带动量的 SGD。这篇博客用可视化的方式,比较了不同梯度下降算法在不同参数设置下的表现。这种可交互的可视化清楚的证明了,深度炼丹师们用脚投的票是非常合理的。很多人都在实践中发现,虽然 Adam 对初始学习率不敏感,训练也比较稳定,但最终能达到的精度没有手动调好的SGD来得高。这可能是因为 Adam 喜欢在极小值附近打圈圈吧。如果大家花费了与调SGD同等的时间来调Adam,可能也会得到比较好的精度,就像最后一张图所示的那样(个人愚见)。

代码开源:

LongGang Pang / learn_deep_learning​gitlab.com
5a7d811b085aa32913df48adccada101.png

此交互动画需要在 Jupyter Notebook 里运行,依赖的库有:numpy, matplotlib, seaborn 以及 ipywidgets。任何人可以开放下载,并在自己的教学演示过程中使用。也欢迎有志之士一起来贡献可视化代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值