2018-07-04 21:19:17 fengchi863 阅读数 395
  • 玩转深度学习实战教程

    玩转深度学习视频培训课程,详细讲解深度学习的原理和利用深度学习框架TensorFlow进行项目实战。课程通过Kaggle竞赛平台的Titanic问题讲解TensorFlow的基本用法以及问题处理的常用技巧,讲解深度学习图像领域的卷积神经网络CNN和多个经典的网络架构、CNN的应用,讲解自然语言处理领域的RNN、LSTM以及它们的多种变种结构,构建语言模型和对话机器人,介绍损失函数和优化深度学习算法在TensorFlow中的实现。

    2864 人正在学习 去看看 王而川

在神经网络中经常面对非凸函数的优化问题,所以在平时经常会用到一些网络的优化方法,包括局部最优、鞍点、梯度悬崖和梯度消失问题。

  1. 对于大规模的神经网络,大多数的局部最优都有一个比较低的损失值,并且寻找真实的全局最优也不是一个很重要的问题,重要的是在参数空间中找到一个相对较低的局部最优值。(因为全局最优可能过拟合严重,局部最优反而可能更好)
  2. 鞍点:是高维数据中一个很突出的问题。鞍点就像是两座山峰的中间区域,该区域不是局部最优值,但是十分平坦,换言之就是梯度几乎为0,无法确定走哪一条路。维度越高,鞍点的数目越是指数型增长。
  3. 梯度悬崖:由于循环神经网络涉及在多个时间段内相乘,所以梯度悬崖在RNN中十分频繁,特别是处理较长的时间序列时。
  4. 梯度消失与梯度爆炸:比如Sigmoid神经元,取值范围为(0,0.25],在梯度反向传播时,当层数较多时,最终导数值已经很小,所以即使网络产生了很大的误差,但底层的神经元依然没有得到足够的误差修正。反之,如果上层的权重过大,当经过传递后,本层的梯度就会变得异常巨大,造成梯度十分不稳定。相比于梯度消失,梯度爆炸的问题比较容易解决,并且发生的情况也不频繁。
  5. 随机梯度下降(SGD):随机梯度下降算法就是选择一条数据,就训练一条数据,然后修改一次权重。为了防止这种随机性带来的危害,我们就多选择几条数据,计算一下多条数据的平均错误,如果某条数据存在严重错误,也会因为多条数据的中和而降低其错误的成都。
  6. 为了防止在最优解附近震荡的现象,我们可以把学习率改为时间衰减的形式。如下式,为训练第k轮时第i轮学习率的取值。
    αi=(1ik)α0+ikb

    当使用这种线性策略来调整学习率时,通常要进行上百轮的学习调整,因此k要大于100,b的取值可以粗略的设置为百分之一的学习率。设置初始学习率很重要,如果太大,学习曲线就会剧烈震荡;如果太小,学习就会非常慢,还可能会陷入一个比较高的代价函数区域。这也是一个鱼和熊掌的问题。
  7. 动量学习法:梯度的物理意义可以理解为,是一个力,带领我们下山,但是我们不是靠力前行,而是靠速度,力只是改变速度的大小和方向,并且速度是可以累积的,所以我们还具有动量。类似于物理学,速度这个参数表示在参数空间移动的方向和速率,而代价函数的负梯度表示参数在参数空间移动的力。引入超参数β,它的值在[0,1]范围之间,用于调节先前梯度(力)的衰减效果。
    v=βvαΔw

    w=w+v

    对上式进行变换,可以得到
    vmax=α||w||1β

    在动量学习法中,每一步走多远依赖的是过去的速度以及当前的力(梯度)。速度v用于累加各轮训练的参数梯度(类似有个加速度),β越大先前梯度对于本轮训练的影响就越大。最终因为衰减因子β的存在,小球在达到最大值以后就会匀速前行。(理解为一个受力平衡的状态)常用的β可以是0.5,0.9.0.99。
    对于β的调整,并没有α的调整中重要,所以不太需要作为超参数进行选择,正常情况下,取值适当即可。
  8. AdaGrad:(个性化的为每一个参数单独的配置学习率)就是将每一维各自的历史梯度的平方叠加起来,然后在更新的时候除以该历史梯度值即可。使用平方的原因是为了去掉梯度的符号,只对梯度的量进行累加。
    AdaGrad很容易受到过去的影响,因为梯度很容易就会累积到比较大的值,所以AdaGrad容易过分降低学习率。
    cachei=cachei+(Δwi)2

    wi=wiαcachei+δΔwi
  9. RMSProp:因为AdaGrad在理论上有比较好的性质,但是对优化神经网络十分不友好,随着训练周期的增长,学习率降低的很快。RMSProp算法在进行梯度累积的时候,会在“过去”和“现在”之间做一个权衡,通过超参数β来条件衰减量,常用取值0.9或0.5。
    cachei=βcachei+(1β)(Δwi)2

    wi=wiαcachei+δΔwi

    RMSProp更新方式对于深度学习网络十分的高效,是深度学习中最有效的更新方式之一。
  10. **Adam:**Adam是指Adaptive moments,其实是Momentum+RMSProp的微调版本。首先计算当前最小批量梯度:
    g=1mj=1mL(y(i),f(x(j);w))w

    类似于动量学习法,设置衰减梯度v:
    v=β1v+(1β1)g

    类似于RMSProp学习法,设置衰减学习率r:
    r=β2r+(1β2)g2

    最后更新参数:
    w=wαr+δv

    因为在开始的时候梯度会非常的小,rv经常会接近于0,所以做下面的“热身”工作:
    vb=v1β1t,rb=r1β2t

    其中,t表示训练的次数,因此仅仅在训练的前几轮中根据就衰减因子来放大各自的值,很快vbrb就会退化成vr
  11. 参数初始化策略:无论使用何种学习方式,都避免不了同一个问题,那就是下山的起始点问题,也就是参数的初始化问题。初始化不仅印象训练效果,还能影响模型的泛化性能(输在起跑线上)。
  12. 应该尽量避免神经元参数出现对称的情况。如果两个神经元使用相同的激活函数,并且输入相同,那么每个神经元都要有不同的参数。否则因为参数相同,在确定的学习算法下,他们的参数的更新也就会相同,出现神经元冗余的情况。
  13. 一般采用均匀分布或者高斯分布的随机初始化方式,分布函数的取值范围(标准差)对优化过程以及泛化能力有着巨大的影响。
    较大的初始化权重范围可以有效避免参数对称线性,减少神经元冗余现象,还可以帮助减轻训练网络时的梯度消失问题,但是太大的初始化权重也会导致梯度爆炸的问题,在一些Sigmoid神经元中,也容易出现过饱和现象,导致修改神经元梯度几乎为0。
  14. 一般参数均值要为0,这是一条高斯分布先验知识。通常,在m输入n输出的单层神经元中,我们可以使用均匀分布对权重进行随机采样初始化。
    Wi,jU(1m,1m)

    或者使用标准初始化:
    Wi,jU(6m+n,6m+n)
  15. 批量归一化:BN层,不能算是一种最优化算法,但是很有用。与选择最小批量梯度下降一样,BN中的“批量”就是采样一小批数据,然后对该批数据在网络各层的输出进行归一化处理。BN的目的就是为了把神经网络每一层的输入数据都调整到均值为零,方差为1的标准正态分布
    Sigmoid在[-2,2]之间的取值是一段近似线性的区域,BN算法所做的就是把输入值尽可能的归一化在激活函数这一狭窄区域。
    BN算法还有另一个步骤,就是将归一化的数据放大,平移回非线性区域。
2019-06-15 21:45:23 x454045816 阅读数 95
  • 玩转深度学习实战教程

    玩转深度学习视频培训课程,详细讲解深度学习的原理和利用深度学习框架TensorFlow进行项目实战。课程通过Kaggle竞赛平台的Titanic问题讲解TensorFlow的基本用法以及问题处理的常用技巧,讲解深度学习图像领域的卷积神经网络CNN和多个经典的网络架构、CNN的应用,讲解自然语言处理领域的RNN、LSTM以及它们的多种变种结构,构建语言模型和对话机器人,介绍损失函数和优化深度学习算法在TensorFlow中的实现。

    2864 人正在学习 去看看 王而川

欢迎关注微信公众号“智能算法” – 原文链接(阅读体验更佳):
深度学习算法(第5期)----深度学习中的优化器选择

上一期,我们一起学习了TensorFlow在训练深度网络的时候怎么解决梯度消失或梯度爆炸的问题,以及怎么尽可能的减少训练时间。
深度学习算法(第4期)---- TF训练DNN之进阶
这期我们继续学习训练深度网络时的一大神器----优化器。学习的路上,我们多多交流,共同进步。本期主要内容如下:

  • Momentum optimization
  • Nesterov Accelerated Gradient
  • AdaGrad
  • RMSProp
  • Adam Optimization

1. 回顾

我们知道在训练一个比较大的深度神经网络的时候,速度上一般都是比较慢的。通过上期的学习,我们已经知道有4中方法可以加速我们的训练过程,如下:

a. 选择一个合适的权重初始化策略
b. 用一个合适的激活函数
c. 运用Batch Normalization策略
d. 复用之前的网络模型

但是今天我们要学习的是另外一个加速神器–优化器,它要比一般的梯度下降算法快很多。我们这里主要介绍几种常见的优化器,其中包括:Momentum optimization,Nesterov Accelerated Gradient,AdaGrad,RMSProp,Adam Optimization。

2. Momentum optimization

2.1 原理

momentum optimization可以翻译为动量优化器,该优化器背后的思想很简单: 假设一个圆球从一个斜坡上滚下去,一开始速度会很慢,但是随着时间的增加,速度会越来越快,考虑到摩擦力和空气阻力,最终会达到一个恒定的速度(空气阻力跟速度的平方成正比)。这就是momentum optimization 背后的思想。跟一般的梯度下降法相比,显然动量优化速度更快。
我们再回顾下一般梯度下降权重的更新是用权重直接减去学习率乘以梯度:

θθηθJ(θ)\theta\leftarrow\theta-\eta{\nabla_\theta}J(\theta)

这种更新权重的方式,并不关心之前的梯度,只根据当前梯度值进行更新。如果当前梯度比较小的话,那么寻优的过程就比较费时。
动力优化根据这一缺点对一般的梯度下降法进行了改进。动力优化更多的考虑了之前的梯度信息,在每一次的迭代中,都会把当前梯度信息加到动力向量mm中,最终根据减去动力向量来更新权重,如下公式:

1.mβm+ηθJ(θ)1.\quad m \leftarrow \beta m+ \eta{\nabla_\theta}J(\theta)
2.θθm2.\quad \theta \leftarrow \theta - m

换句话说,这里把梯度当做是加速度而并不是速度,为了模拟一些摩擦力和阻力来防止速度变得过大,该算法增加了一个超参数β\beta,该值的取值范围为0~1,当β=0\beta=0时表示较高的阻力,此时梯度的更新等同于一般的梯度优化。当β=1\beta=1的时候表示没有阻力,此时梯度更新最快,一般情况下该值设置为0.9.
从上面公式可以看出,假如梯度恒定为\nabla的话,权重更新的最终速度为11βη\frac 1 {1- \beta} \eta{\nabla}。假如β=0.9\beta=0.9的话,那么momentum optimization的最终优化速度是一般梯度下降的10倍左右。这就使的动力优化比一般梯度优化能够更快的逃离平坦区域。
由于动力加速度的存在,所以在寻优的时候可能会超过最优点一点,然后返回,再超过,再返回最终稳定在最优点。这就是为什么要在算法中加入超参数β\beta的一个原因,它能够减少震荡加速收敛。

2.2 实现

在TensorFlow中实现Momentum Optimization比较简单,如下:

optimizer = tf.train.MomentumOptimizer(learning_rate=learning_rate,
                                        momentum=0.9)

动力优化的一个缺点就是多了一个超参数β\beta去调节。然而,这个超参数一般情况下设置为0.9就能够很好的工作,并不需要经常去调节。

3. Nesterov Accelerated Gradient

3.1 原理

Nesterov Accelerated Gradient(NAG)算法,其实是对Momentum Optimization的一个小小的改进,在动力优化中,更新动力变量mm是在当前(θ\theta)的梯度上进行更新的,而在NAG算法中,对动力变量的更新在动力方向上稍微提前了一些(θ+βm\theta + \beta m),如下:

1.mβm+ηθJ(θ+βm)1.\quad m \leftarrow \beta m+ \eta{\nabla_\theta}J(\theta + \beta m)
2.θθm2.\quad \theta \leftarrow \theta - m

上面的改进是可行的原因就在于,Momentum Optimization中的动力向量$m$的方向是指向最优点的,因此用更前一点的梯度来代替当前的梯度去更新动力向量更为精确。如下图:在这里插入图片描述
上图中,1\nabla_1代表损失函数在起始点θ\theta的梯度,而2\nabla_2代表损失函数在点θ+βm\theta + \beta m的梯度值,可以看到NAG更接近最优点,随着时间的累积,NAG会比动力优化器明显的更快一些。此外我们还可以看到,当动力向量推动权重接近最优值的时候,1\nabla_1会继续加速推动,使得远离最优值,而2\nabla_2则已经开始往回拉了,这就减少了震荡进而使得更快收敛。

3.2 实现

在training深度网络的时候,NAG通常会比Momentum Optimization更快收敛,用起来也比较简单只需要将动力优化器中设置参数use_nesterov=Trueuse\_nesterov=True即可,如下:

optimizer = tf.train.MomentumOptimizer(learning_rate=learning_rate,
                    momentum=0.9, use_nesterov=True)

4. AdaGrad

4.1 原理

考虑到之前介绍的细长碗的最优化这个问题,一般的梯度优化会在陡峭的区域快速下降,而在平坦区域慢慢走向最优值。如果算法能够提前监测到这种情况就会更好,就可以在陡峭的地方慢慢下降(防止错过最优点),在平坦区域快速通过,这样就能更快的找到最优点。AdaGrad算法就是通过衰减学习率来进行达到这个目的的。公式原理如下:

1.ss+θJ(θ)θJ(θ)1.\quad s \leftarrow s + {\nabla_\theta}J(\theta) \otimes {\nabla_\theta}J(\theta)
2.θθηθJ(θ)s+ε2.\quad \theta \leftarrow \theta - \eta {\nabla_\theta}J(\theta) \oslash {\sqrt{s+\varepsilon}}

上面公式1中在ss中累加了梯度的平方,(\otimes表示矩阵中对应元素相乘),而在公式2中和之前的梯度下降比较类似,唯一不同的是对梯度向量进行了衰减或者说是对学习率η\eta做了衰减(\oslash表示矩阵中对应元素相除,而ε\varepsilon则是防止除数为0,通常设置为101010^{-10})。
换句话说就是AdaGrad算法对学习率进行了自适应化,当梯度比较大的时候,学习率就比较小,而当梯度比较小的时候,学习率就比较大。如下图,该算法能够更明显的向最优点逼近。
image
然而事实证明,AdaGrad算法在一些简单的二项式问题上表现优异,但是在training深度网络的时候,由于学习率衰减过多,常常会过早停止寻优。因此,尽管TensorFlow中有提供该方法AdaGradOptimizerAdaGradOptimizer,但是不建议用该优化器去训练深度网络。因此这里就不写出实现代码了。

5. RMSProp

5.1 原理

尽管AdaGrad算法衰减过快而导致无法收敛到最优点的问题,RMSProp算法通过修改AdaGrad算法第一步的梯度累加方式,改累加所有的梯度为对累加的梯度乘以一个衰减系数,如下公式:

1.sβs+(1β)θJ(θ)θJ(θ)1.\quad s \leftarrow \beta s + (1 - \beta){\nabla_\theta}J(\theta) \otimes {\nabla_\theta}J(\theta)
2.θθηθJ(θ)s+ε2.\quad \theta \leftarrow \theta - \eta {\nabla_\theta}J(\theta) \oslash \sqrt{s+\varepsilon}

可知,该方法又多了一个超参数衰减率β\beta,一般设置为β=0.9\beta=0.9。理解了AdaGrad算法,这里就不再过多解释了。

5.2 实现

当然,TensorFlow对该算法也是有提供的,如下:

optimizer = tf.train.RMSPropOptimizer(learning_rate=learning_rate,
                            momentum=0.9, decay=0.9, epsilon=1e-10)

这个方法的表现还是不错的,在简单问题上表现优于AdaGrad算法,一般情况下性能也优于Momentum Optimization和NAG方法。事实上,在Adam算法出现之前,这个方法是一般训练网络时候的最优选则。

6. Adam Optimization

6.1 原理

Adam代表adaptive moment estimation,结合了Momentum Optimization和RMSProp的思想。运用了动力优化方法中的利用历史梯度信息,和RMSProp中利用历史历史梯度的平方的相关信息,公式如下:

1.mβ1m+(1β1)θJ(θ)1.\quad m \leftarrow \beta_1 m+ (1 - \beta_1){\nabla_\theta}J(\theta)
2.sβ2s+(1β2)θJ(θ)θJ(θ)2.\quad s \leftarrow \beta_2 s + (1 - \beta_2){\nabla_\theta}J(\theta) \otimes {\nabla_\theta}J(\theta)
3.mm1β1T3.\quad m \leftarrow \frac {\bm m} {1 - {\beta_1}^T}
4.ss1β2T4.\quad s \leftarrow \frac {\bm s} {1 - {\beta_2}^T}
5.θθηms+ε5.\quad \theta \leftarrow \theta - \eta m \oslash \sqrt{s+\varepsilon}

从上面1,2,5公式可以看出,该算法跟Momentum Optimization和RMSProp特别像,唯一不同的是在公式1中运用了历史梯度指数衰减的均值而不是历史梯度指数衰减的和。公式3,4其实是一个小技巧点,因为一般m\bm ms\bm s会被初始化为0,所以在training开始的时候回一直偏向0,公式3,4能够在training初期快速提高这两个变量值。
上公式中多了3个超参数β1,β2,ε\beta_1, \beta_2, \varepsilon,这三个参数一般设置为0.9,0.99和10810^{-8}.

6.2 实现

在Tensorflow中用法都是很简单,所有参数都为默认值的情况下如下:

optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)

其实Adam算法是一个自动调节学习率的算法,一般可以将学习率设置为0.001.事实证明该算法在一般深度网络中是优选择。

7. 小结

我们从一般梯度下降出发,一起学习了最近比较常见的优化器,包括Momentum Optimization, Nesterov Accelerated Gradient, AdaGrad, RMSProp和Adam Optimization。其中Adam算法是目前在training深度网络中的优选。


(如需更好的了解相关知识,欢迎加入智能算法社区,在“智能算法”公众号发送“社区”,即可加入算法微信群和QQ群)
image

2019-01-13 13:16:51 weixin_40759186 阅读数 125
  • 玩转深度学习实战教程

    玩转深度学习视频培训课程,详细讲解深度学习的原理和利用深度学习框架TensorFlow进行项目实战。课程通过Kaggle竞赛平台的Titanic问题讲解TensorFlow的基本用法以及问题处理的常用技巧,讲解深度学习图像领域的卷积神经网络CNN和多个经典的网络架构、CNN的应用,讲解自然语言处理领域的RNN、LSTM以及它们的多种变种结构,构建语言模型和对话机器人,介绍损失函数和优化深度学习算法在TensorFlow中的实现。

    2864 人正在学习 去看看 王而川

简单概括参数更新:

1、更新方向不是简单地取为梯度
2、学习速率不是简单地取为常值

都是使用局部梯度delta来更新参数:
在这里插入图片描述
我们一般使用修正后的delta:
在这里插入图片描述

优化器

Vanilla Update:

和最普通的梯度下降法别无二致:
在这里插入图片描述

Vanilla 代码实现:

class MBGD(Optimizer):
    def run(self, i, dw):
        return self.lr * dw

Momentum Update:

在这里插入图片描述
其中梯度Δwt的物理意义即为“动力”、vt的物理意义即为第 t 步迭代中参数的“行进速度”、ρ的物理意义即为惯性,它描述了上一步的行进速度会在多大程度上影响到这一步的行进速度。易知当ρ=0时、Momentum Update等价于 Vanilla Update。

Momentum 代码实现:

class Momentum(Optimizer, metaclass=TimingMeta):
    """
        初始化结构(Momentum Update版本)
        self._momentum:记录“惯性”的属性
        self._step:每一步迭代后“惯性”的增量
        self._floor、self._ceiling:“惯性”的最小、最大值
        self._cache:对于Momentum Update而言、该属性记录的就是“行进速度”
        self._is_nesterov:处理Nesterov Momentum Update的属性,这里暂时按下不表
    """
    def __init__(self, lr=0.01, cache=None, epoch=100, floor=0.5, ceiling=0.999):
        Optimizer.__init__(self, lr, cache)
        self._momentum = floor
        self._step = (ceiling - floor) / epoch
        self._floor, self._ceiling = floor, ceiling
        self._is_nesterov = False
    def run(self, i, dw):
        dw *= self.lr
        velocity = self._cache
        velocity[i] *= self._momentum
        velocity[i] += dw
        return velocity[i]
    def update(self):
        if self._momentum < self._ceiling:
            self._momentum += self._step

Nesterov Momentum Update:

在这里插入图片描述

Nesterov Momentum 代码实现:

class NAG(Momentum):
    def __init__(self, lr=0.01, cache=None, epoch=100, floor=0.5, ceiling=0.999):
        Momentum.__init__(self, lr, cache, epoch, floor, ceiling)
        self._is_nesterov = True
        
    def run(self, i, dw):
        dw *= self.lr
        velocity = self._cache
        velocity[i] *= self._momentum
        velocity[i] += dw
        # 如果不是Nesterov Momentum Update、可以直接把当成更新步伐
        if not self._is_nesterov:
            return velocity[i]
        # 否则、调用公式来计算更新步伐
        return self._momentum * velocity[i] + dw

RMSProp Update:

RMSProp 方法与 Momentum 系的方法最根本的不同在于:Momentum 系算法是通过搜索更优的更新方向来进行优化、而 RMSProp 则是通过实时调整学习速率来进行优化。
在这里插入图片描述如果徘徊回了原点自然需要奋发图强地开辟新天地、如果已经走了很远自然应该谨小慎微。

NRMSProp 代码实现:

class RMSProp(Optimizer):
    """
        初始化结构(RMSProp版本)
        self.decay_rate:记录的属性,一般会取0.9、0.99或0.999
        self.eps:算法的平滑项、用于增强算法稳定性,通常取中的某个数
        self._cache:对于RMSProp而言、该属性记录的就是中间变量
    """
    def __init__(self, lr=0.01, cache=None, decay_rate=0.9, eps=1e-8):
        Optimizer.__init__(self, lr, cache)
        self.decay_rate, self.eps = decay_rate, eps
    def run(self, i, dw):
        self._cache[i] = self._cache[i] * self.decay_rate + (1 - self.decay_rate) * dw ** 2
        return self.lr * dw / (np.sqrt(self._cache[i] + self.eps))

Adam Update:

从直观上来说、Adam 算法很像是 Momentum 系算法和 RMSProp 算法的结合(中间变量Δ的相关计算类似于 Momentum 系算法对更新方向的选取、中间变量∇的相关计算则类似于 RMSProp 算法对学习速率的调整)。
在这里插入图片描述

Adam 代码实现:

class Adam(Optimizer):
    """
        初始化结构(Adam版本)
        self.beta1、self.beta2:记录、的属性,一般会取、
        self.eps:意义与RMSProp中的eps一致、常取
        self._cache:对于Adam而言、该属性记录的就是中间变量和中间变量
    """
    def __init__(self, lr=0.01, cache=None, beta1=0.9, beta2=0.999, eps=1e-8):
        Optimizer.__init__(self, lr, cache)
        self.beta1, self.beta2, self.eps = beta1, beta2, eps
    def feed_variables(self, variables):
        self._cache = [
            [np.zeros(var.shape) for var in variables],
            [np.zeros(var.shape) for var in variables],
        ]
    def run(self, i, dw):
        self._cache[0][i] = self._cache[0][i] * self.beta1 + (1 - self.beta1) * dw
        self._cache[1][i] = self._cache[1][i] * self.beta2 + (1 - self.beta2) * (dw ** 2)
        return self.lr * self._cache[0][i] / (np.sqrt(self._cache[1][i] + self.eps))

优化器工厂

我们可以实现一个简单的工厂来“生产”这些优化器:

class OptFactory:
    # 将所有能用的优化器存进一个字典
    available_optimizers = {
        "MBGD": MBGD,
        "Momentum": Momentum, "NAG": NAG,
        "RMSProp": RMSProp, "Adam": Adam,
    }
    # 定义一个能通过优化器名字来获取优化器的方法
    def get_optimizer_by_name(self, name, variables, lr, epoch):
        try:
            _optimizer = self.available_optimizers[name](lr)
            if variables is not None:
                _optimizer.feed_variables(variables)
            if epoch is not None and isinstance(_optimizer, Momentum):
                _optimizer.epoch = epoch
            return _optimizer
2017-09-14 15:32:20 chanbupt 阅读数 840
  • 玩转深度学习实战教程

    玩转深度学习视频培训课程,详细讲解深度学习的原理和利用深度学习框架TensorFlow进行项目实战。课程通过Kaggle竞赛平台的Titanic问题讲解TensorFlow的基本用法以及问题处理的常用技巧,讲解深度学习图像领域的卷积神经网络CNN和多个经典的网络架构、CNN的应用,讲解自然语言处理领域的RNN、LSTM以及它们的多种变种结构,构建语言模型和对话机器人,介绍损失函数和优化深度学习算法在TensorFlow中的实现。

    2864 人正在学习 去看看 王而川

注:文章内容译自斯坦福大学cs231n课程,只翻译了原文的一部分。
原文请访问:
http://cs231n.github.io/neural-networks-3/#sgd
·······················································································································

随机梯度下降方法及其变种

Vanilla update

最简单的更新方式,沿着负梯度的方向更新参数(梯度指示着函数增长的方向,但我们通常是要最小化损失函数的),假设我们要更新的参数x和其梯度dx,则参数更新的形式如下:

x += -learning_rate * dx
Momentum update

这里的learning rate是个超参数–一个固定的常数。

动量更新是在深度网络中常常收敛更快的一种方法。这种方法收到物理学中动量的启发,可以从物理的角度来看待优化问题。特别地,损失可以解释为丘陵地形的高度(并且因此也可以解释为势能Uαh,因为U = mgh)。用随机数初始化参数等同于在某个位置设置零初始速度的粒子。然后可以将优化过程视为与在横向上滚动的模拟参数矢量(即,粒子)的过程。
由于粒子上的力与势能的梯度(即F =-∇U)有关,所以粒子受到的力恰好是损失函数的(负)梯度。此外,F = ma,所以(负)梯度在该视图中与粒子的加速度成比例。 请注意,这不同于上面显示的SGD更新,其中渐变直接集成了位置。 相反,从物理角度提出了一个更新:梯度只能直接影响速度,而速度又对位置产生影响:

v = mu * v – learning_rate *dx # 整合后的速度
x += v # 整合后的位置

在这里,我们看到一个初始化为零的v变量和一个额外的超参数(μ)的介绍。 作为一个不幸的误称,这个变量在优化中被称为动量(其典型值约为0.9),但其物理意义与摩擦系数更为一致。实际上,该变量减速并降低系统的动能,否则粒子永远不会停在山底。 当交叉验证时,该参数通常设置为[0.5,0.9,0.95,0.99]等值。与学习率的退火计划类似(稍后讨论),优化有时可以从动量计划中获益,其中在后期的学习阶段动量增加。 一个典型的设置是从大约0.5的动量开始,并在多个时期退火到0.99左右。
“With Momentum update, the parameter vector will buildup velocity in any direction that has consistent gradient.(随着动量的更新,参数向量将会建立起在所有方向上都恒定梯度的速度)”

Nesterov Momentum

Nesterov动量是与动量更新略微不同的一个版本,最近变得流行起来。它对凸函数的收敛有着很强的理论保证,并且实践中也比标准的动量更新方式效果稍微更好些。
Nesterov动量更新的关键思想是,当目前的参数在某个位置x时,我们知道单独的动量项(即忽略具有梯度的第二项)即将推动参数 矢量由mu * v。因此,我们要计算梯度时,我们可以将未来的近似位置x + mu * v视为“前瞻”(lookahead) - 这是我们即将到达的地方附近。因此,计算在x + mu * v处的梯度比“旧”的位置x上的梯度更有意义。

因此,我们将会做如下的计算:

X_head = x + mu * v
v = mu * v – learning_rate *dx_ahead
x += v

参数自适应学习方法

   我们迄今为止所讨论的所有以前的方法在全局和所有参数中均衡地学习了学习率。调整学习率是一个昂贵的过程,因此设计可以自适应地调整学习率的方法,甚至每个参数都做了很多工作。 这些方法中的许多可能仍然需要其他超参数设置,但是论点是相比原始学习速率,他们对于范围更广泛的超参数值表现更好。

Adagrad

Adagrad是一种学习率自适应的方法,最早由 Duchi等人提出。工作方式如下:
假设梯度为dx,参数向量为x, eps为一个很小的数防止分母为0

cache+= dx**2
x +=-learning_rate * dx / (np.sqrt(cache) + eps)

请注意,变量cache的维度和梯度的维度一样,可以跟踪每个参数的梯度平方和。然后,将其用于对每个维度的参数更新步骤进行归一化。 请注意,大的梯度的权重将降低有效的学习率,而小的或不频繁更新的权重将提高其有效的学习率。 有趣的是,平方根操作是非常重要的,没有它,算法执行得更糟。平滑项eps(通常设置在1e-4到1e-8的范围内)避免除以零。 Adagrad的缺点是在深度学习中,单调下降的学习率通常太激进,导致学习太早停止。

RMSporp

RMSprop是一种非常有效的,但目前尚未发布的自适应学习率方法。 RMSProp更新以非常简单的方式调整Adagrad方法,以减少其激进,单调降低的学习率。特别地,它使用平均渐变的移动平均值,给出:

cache = decay_rate * cache +(1 – decay_rate) * dx**2
x += -learning_rate * dx /(np.sqrt(cache) + eps)

这里,decay_rate是一个超参数,典型取值为[0.9,0.99,0.999]。请注意,‘x + =’的更新与Adagrad相同,但cache变量为一种“泄漏”的方式。因此,RMSProp仍然基于其渐变的幅度调整每个权重的学习率,这具有有益的均衡效果,但与Adagrad不同,更新不会单调变小。

Adam

Adam是最近提出的,看起来像RMSProp的一种基于动量的方法。 (简化版)更新方法如下所示:

m = beta1 * m + (1-beta1)* dx # 动量
v = beta2 * v + (1-beta2) *(dx**2) # cache
x += -learning_rate * m /(np.sqrt(v) + eqs)

请注意,更新完全与RMSProp相同,不同之处在于使用梯度的“平滑”版本m,替代原始(也许有噪声)梯度向量dx。本文中的推荐值为eps = 1e-8,beta1 = 0.9,beta2 = 0.999。 在实践中,Adam目前被推荐为使用默认算法,并且通常比RMSProp略好。 然而,经常也值得尝试SGD + Nesterov动量作为替代。完整的Adam更新还包括一个偏差校正机制,补偿这个现象:最初的几个时间步长中,向量m,v都被初始化,因此在完全“预热”之前都被偏置为零。 利用偏差校正机制,更新如下:(t 是迭代的步数)

m = beta1*m + (1-beta1)*dx
mt = m / (1-beta1**t)
v = beta2*v +(1-beta2)*(dx**2)
vt = v / (1-beta2**t)
x += - learning_rate * mt /(np.sqrt(vt) + eps)

注意到,现在Adam也是迭代步数t的函数了。

各种参数更新方法的可视化

图-1.

图-2.
可以帮助您建立直觉的学习过程动态的动画。 上图:不同优化算法的损耗曲面和时间演化的轮廓。 注意到基于动量的方法的“overshooting”行为,这使得优化看起来像一座滚下山的球。下图:优化中鞍点的可视化,其中沿着不同维度的曲率具有不同的符号(一维向上和向下弯曲)。 注意,SGD很难打破对称,被困在顶部。 相反,诸如RMSprop的算法在鞍形方向上将看到非常低的梯度。 RMSprop中的分母项将提高沿此方向的有效学习率,从而帮助RMSProp进行优化。图片来源:Alec Radford(https://twitter.com/alecrad)。

2018-09-19 20:19:17 SoundSlow 阅读数 1173
  • 玩转深度学习实战教程

    玩转深度学习视频培训课程,详细讲解深度学习的原理和利用深度学习框架TensorFlow进行项目实战。课程通过Kaggle竞赛平台的Titanic问题讲解TensorFlow的基本用法以及问题处理的常用技巧,讲解深度学习图像领域的卷积神经网络CNN和多个经典的网络架构、CNN的应用,讲解自然语言处理领域的RNN、LSTM以及它们的多种变种结构,构建语言模型和对话机器人,介绍损失函数和优化深度学习算法在TensorFlow中的实现。

    2864 人正在学习 去看看 王而川

单纯以算法为论,深度学习从业者的算法能力可能并不需要太大,因为很多时候,只需要构建合理的框架,直接使用框架是不需要太理解其中的算法的。但是我们还是需要知道其中的很多原理,以便增加自身的知识强度,而优化器可能正是深度学习的算法核心


本文基本完全参考以下连接:
原理简化讲解篇:https://morvanzhou.github.io/tutorials/machine-learning/ML-intro/3-06-speed-up-learning/
使用经验篇:https://zhuanlan.zhihu.com/p/22252270
优化器tensorflow官方文档:https://www.tensorflow.org/api_guides/python/train


官方文档所给的优化器很多,而且后续也在不停地添加当中,因此,我这里只列举基础和常用的几个:
优化器比较
优化器分类:

  • Stochastic Gradient Descent (SGD):随机梯度,分批,随机放入一批,而不是全部放入,加快训练速度,却不会大大影响效果

  • Optimizer 主类:

    • GradientDescentOptimizer :实现梯度下降算法的优化器。(结合理论可以看到,这个构造函数需要的一个学习率就行了)
    • MomentumOptimizer
      Momentum单词即动量、动力,这里的意思可以理解为惯性,想象一下,如果你现在从山上玩下冲,你的目的是到达最低点,但是如果这个山坡并不是直线梯度下降,而是局部左拐右拐梯度下降,这样将导致下降步骤是个折线形,大大降低训练速度,这也是基本梯度下降算法的缺点,因此这里引入了动量因子。
      所以你下山有之前的动量,即便你想拐弯都拐不了很大
      比如:原来的梯度计算是:variable -= learning_rate * gradient;
      现在变为:variable -= learning_rate * (momentum * accumulation + gradient)
      这里的momentum * accumulation是之前的动量积累,所以就导致即便局部有折线,也会由于之前的动量影响太大,而尽量保持直线下降
      源码公式:
      accumulation = momentum * accumulation + gradient
      variable -= learning_rate * accumulation
      或者直接是:W += b1 * m -Learning rate * dx
    • AdagradOptimizer
      公式变化如下:
      W += -Learning rate * dx
      变为:
      v += dx^2
      W += -Learining rate * dx /sqrt(v)
      ada-即单词Adaptive,中文:自适应
      同增加惯性因子的原理类似,此方法也是为了减轻局部偏折,但是作用在学习率上。即为了防止偏折过大,我们会首先计算偏折幅度-即梯度值,并将其作为学习率分母参数。意思就是,如果梯度很大,学习率就很低,这样防止偏折过大;梯度很小,学习率就大。
    • AdagradDAOptimizer 略
  • RMSPropOptimizer
    AdaGrad阻力因子考虑了当前的梯度,并没有考虑之前的梯度系数,这样会导致不管是迭代100次的或者是迭代10000次的,阻力都是一样的,没有区别。如果是运行到接近最优化处,其实阻力应该更大一些,因为此时只需要微调就行,所以这里增加了一个全局梯度累计,这样,梯度阻力会随着迭代的次数不断增大。
    可能做到的改进:AdaGrad阻力因子没有考虑一个特殊情况,即如果下山最大梯度确实有个很大的90度折线,而且这个折线正是全局梯度方向,但是由于这个阻力因子的存在,可能每次梯度都很大,每次都阻碍,反而降低了下降速度,所以,这里可以添加了一个占比系数,即不仅仅考虑当前的梯度值,而且还要考虑之前的梯度值,这样,当梯度值一直很大时,说明可能是对的道路,阻力相应就减小。
    公式:
    V = b2* V +(1-b2) * dx^2
    W += -Learining rate * dx /sqrt(v)

  • AdamOptimizer
    Adam联合了momentum 的惯性原则 , 加上 adagrad 的对错误方向的阻力
    公式:
    M += b1 * m -Learning rate * dx (momentum)
    V = b2* V +(1-b2) * dx^2 (AdaGrad)
    W += -Learining rate * M /sqrt(V)

深度学习优化方法

阅读数 278

没有更多推荐了,返回首页