找回密码
 立即注册
  • QQ空间
  • 回复
  • 收藏

深度学习中7种最优化算法的可视化与理解

admin 2020-8-5 08:27 102人围观 C++相关


加入极市专业CV交流群,与 10000+来自港科大、北大、清华、中科院、CMU、腾讯、百度 等名校名企视觉开发者互动交流!

同时提供每月大咖直播分享、真实项目需求对接、干货资讯汇总,行业技术交流。关注 极市平台 公众号 ,回复 加群,立刻申请入群~
作者丨小小鱼@知乎来源丨https://zhuanlan.zhihu.com/p/41799394

本文旨在优化一维函数,实际上模型参数有数百万维以上,差距很大,因此本文最好作为辅助法的理解,而非对算法优劣的判断依据。

在深度学习中,有很多种优化算法,这些算法需要在极高维度(通常参数有数百万个以上)也即数百万维的空间进行梯度下降,从最开始的初始点开始,寻找最优化的参数,通常这一过程可能会遇到多种的情况,诸如:

1、提前遇到局部最小值从而卡住,再也找不到全局最小值了。

2、遇到极为平坦的地方:“平原”,在这里梯度极小,经过多次迭代也无法离开。同理,鞍点也是一样的,在鞍点处,各方向的梯度极小,尽管沿着某一个方向稍微走一下就能离开。

3、“悬崖”,某个方向上参数的梯度可能突然变得奇大无比,在这个地方,梯度可能会造成难以预估的后果,可能让已经收敛的参数突然跑到极远地方去。

为了可视化&更好的理解这些优化算法,我首先拼出了一个很变态的一维函数:

其导数具有很简单的形式:

具体长得像:



具有悬崖和大量的局部最小值,足以模拟较为复杂的优化情况了。

算法1:纯粹的梯度下降法


该算法很简单,表述如下:
    首先给出学习率lr,初始x while True: x = x - lr*df/dx
    根据学习率的不同,可以看到不同的效果。学习率过小,卡在局部极小值,学习率过大,压根不收敛。


    梯度下降法

    算法2:梯度下降法+动量


    算法在纯粹的梯度下降法之上,外加了梯度,从而记录下了历史的梯度情况,从而减轻了卡在局部最小值的危险,在梯度=0的地方仍然会有一定的v剩余,从而在最小值附近摇摆。
      首先给出学习率lr,动量参数m 初始速度v=0,初始x while True: v = m * v - lr * df/dx x += v
      下面可以看图:



      梯度下降+动量, lr=0.05



      梯度下降+动量, lr=0.01


      梯度下降+动量, lr=0.002

      从中我们可以看出:
      1、lr越小越稳定,太大了很难收敛到最小值上,但是太小的话收敛就太慢了。2、动量参数不能太小,0.9以上表现比较好,但是又不能太大,太大了无法停留在最小值处。

      算法3:AdaGrad算法


      AdaGrad算法的思想是累计历史上出现过的梯度(平方),用积累的梯度平方的总和的平方根,去逐元素地缩小现在的梯度。某种意义上是在自行缩小学习率,学习率的缩小与过去出现过的梯度有关。

      缺点是:刚开始参数的梯度一般很大,但是算法在一开始就强力地缩小了梯度的大小,也称学习率的过早过量减少。

      算法描述:
        给出学习率lr,delta=1e-7累计梯度r=0,初始xwhile True: g = df/dx r = r + g*g x = x - lr / (delta+ sqrt(r)) * g



        效果并不是很好......

        算法4:RMSProp


        AdaGrad算法在前期可能会有很大的梯度,自始至终都保留了下来,这会使得后期的学习率过小。RMSProp在这个基础之上,加入了平方梯度的衰减项,只能记录最近一段时间的梯度,在找到碗状区域时能够快速收敛。

        算法描述:
          给出学习率lr,delta=1e-6,衰减速率p累计梯度r=0,初始xwhile True: g = df/dx r = p*r + (1-p)*g*g x = x - lr / (delta+ sqrt(r)) * g


          RMSProp,p=0.99


          RMSProp,p=0.9



          RMSProp,p=0.8

          衰减速率情况复杂,建议自行调参.......

          算法5:Adam算法


          Adam算法和之前类似,也是自适应减少学习率的算法,不同的是它更新了一阶矩和二阶矩,用一阶矩有点像有动量的梯度下降,而用二阶矩来降低学习率。

          此外还使用了类似于s = s / (1-p1^t)这样的公式,这样的公式在t较为小的时候会成倍增加s,从而让梯度更大,参数跑的更快,迅速接近期望点。而后续t比较大的时候,s = s / (1-p1^t)基本等效于s=s,没什么用。

          算法如下:
            给出学习率lr,delta=1e-8,衰减速率p1=0.9,p2=0.999 累计梯度r=0,初始x ,一阶矩s=0,二阶矩r=0时间t = 0while True: t += 1 g = df/dx s = p1*s + (1-p1) *g r = p2*r +(1-p2)*g*g
            s = s / (1-p1^t) r = r / (1-p2^t)
            x = x - lr / (delta+ sqrt(r)) * s


            Adam算法,鬼一样的表现

            是的,你没有看错,这玩意压根不收敛......表现极差。

            在算法中仔细研究后才发现,是在t很小的前几步的时候,p2=0.999太大了,导致r = r / (1-p2^t) 中,1-p2^t接近0,r迅速爆炸,百步之内到了inf。后来修改p2=0.9后效果就好得多了。



            Adam算法,神级表现

            最后还是Adam效果最好了 :),尽管学习率还是需要相当的调参。

            算法6:牛顿法


            牛顿法是二阶近似方法的一种,其原理类似于将某函数展开到二次方(二次型)项:

            鲜花

            握手

            雷人

            路过

            鸡蛋

            yafeilinux和他的朋友们微信公众号二维码

            微信公众号

            专注于Qt嵌入式Linux开发等。扫一扫立即关注。

            Qt开源社区官方QQ群二维码

            QQ交流群

            欢迎加入QQ群大家庭,一起讨论学习!

            我有话说......