[Hinton] Neural Networks for Machine Learning - Converage

Link: Neural Networks for Machine Learning - 多伦多大学

Link: Hinton的CSC321课程笔记

Ref: 神经网络训练中的Tricks之高效BP (反向传播算法)

关于梯度下降的东西,涉及的知识很多,有必要单独一章


 

Lecture 06

—— mini批量梯度训练及三个加速的方法 (详见链接)

  

一、mini-批量梯度下降概述

这部分将介绍使用随机梯度下降(SGD)学习来训练NN,着重介绍mini-批量版本,而这个也是现今用的最广泛的关于训练大型NN的方法。这里再回顾下关于一个线性神经元他的错误表面是怎样的。

 

提出问题

最速下降的方向不是指向我们所希望的(上图中黑色箭头,我们希望指向绿色点的,但是按照局部梯度来说却是黑色箭头指示的方向)。

我们所希望的是在红色指向绿色的方向走一大步,而不是横跨上图中的椭圆的部分,最后会使得学习时间很长,而且一直在左右动荡,而正确的梯度方向却每次只迈进一小步,这明显不符合我们的想法。

 

解决问题 - mini batch

如果有一个高度冗余的数据集,并在前一半的数据集上计算一个权重的梯度,那么就可能发生即使在后半数据集上计算这个权重的梯度和前面得到的值是一样的。所以相比较发现在整个数据集上计算梯度是浪费时间的,

    • 更好的方法就是在数据的子集上计算梯度,然后更新权值,然后在剩下的数据上计算更新后权值的梯度,
    • 如果将这个方法发挥到极限,那么就是一个样本上计算梯度,然后更新权值,然后计算下一个样本在基于上一个样本得到的权值上的梯度。

Sol: 通常来说,一般不会这么极限,所以通常更好的方法是用小型mini批量,通常是10,100或者甚至1000个样本。mini批量的好处是与“online”方法相比,

    • 在更新权值上的计算量更少;
    • 另一个优势就是当计算梯度的时候,可以以并行的方式计算这一整群样本(一个mini 批量)的梯度,大多数计算机都擅长矩阵,矩阵乘法,这就能够让我们考虑一整群训练样本,并在同一时间将这个权值应用于这一整群训练样本去得到激活值 并输入给NN的下一层。矩阵乘法在GPU上可以更加的高效。

但是在使用mini批量的时候,不希望在一个mini批量中答案总是一样的,并且不希望在下一个mini批量中有着不同的但是还是总是一样的答案(这句话没懂,但是按照下面的意思就是在考虑类别数量的时候权衡mini批量中不同类别的所占比例)。这也会导致权重会有没必要的动荡。理想情况是,如果有10类,那么设置mini批量的大小是10或者100,这样可以使得在一个mini批量中每个类别有着相同的样本量

一种能够逼近这种选择方法的方法就是先在所有样本的基础上进行随机排序,然后随机抓取mini-批量,但是需要避免在整个数据集上无特点的mini'批量,因为这时候不管怎么抓取,mini批量的包含类别都是同一类。

【总之,好的样本要内部多样、均衡】

 

但是当有着一个高度冗余和大型训练集,选择mini批量梯度学习方法总是人们优先考虑的,也许mini批量会很大(就是总样本除以每个mini批量的尺寸),但是相比较而言mini批量总是更具效率。 

 

这就是人们面对一个大的冗余数据集的时候在大NN上选择的训练方法,

    • 开始是先猜测一个初始化的学习率
    • 然后观察这个网络的学习结果是否满意,还是越来越坏,如果越来越坏,或者疯狂的振荡,那么就减小学习率
    • 如果这个误差下降的很慢,比如在验证集合上发现误差下降的趋势很慢。因为mini批量的方法是对所有梯度的一个粗略估计,所以你希望误差在验证集上的表现是波动很小的,所以不希望每次误差上升的时候才减小学习率,但是却也希望误差可以相对连续不断的下降。所以如果误差的下降曲线是连续但是缓慢的,那么就可以增大学习率,如果仔细研究这个工作原理,那么就可以写个简单的程序来自动调节学习率。
    • 但是不管怎么说,在mini批量学习的末尾,调小学习率总是没错的。这是因为权重中的波动来自于梯度中的波动,而这又来自于mini-批量,并且希望得到一个最终的权重集合作为一个满意的参数,所以当调小学习率的时候,可以将这些波动给平滑掉,并且得到一个对于许多mini批量都好的最终权重集合。

 

所以调小学习率的一个好时机就是当误差停止持续不断的下降的时候;一个认为误差停止下降的较好的准则就是在一个独立的验证集合上使用这个误差(即训练到这时候得到的参数集和用来验证集上的预测)。

也就是说,这个验证集合既不是用来训练,也不是用来做最后测试的集合。【验证集合+训练集合+测试集合】

 

二、关于mini-批量梯度下降的技巧

第一、如何在自己的网络中进行权重等参数的初始化

如果两个隐藏单元有着一样的权值,一样的偏置,并且接受的输入都是一样的,那么就没必要区别对待,因为他们的梯度也是一样的,所以希望他们学到不同的特征检测器,那么就需要将它们区别对待。

这里可以采用很小的随机权值来对权重初始化,以此来打破对称性,而且这些小的随机权重不需要相互之间有一样的尺寸

所以如果有一个隐藏单元有着很大的fan-in

Fan-in is a term that defines the maximum number of digital inputs that a single logic gate can accept. Most transistor-transistor logic ( TTL ) gates have one or two inputs, although some have more than two. A typical logic gate has a fan-in of 1 or 2.

按照解释,那么意思就是:这个输入单元所涉及的权重的数量

如果使用相当大的权值的话,它会使得这个单元倾向于饱和(那么就会使得网络过拟合):

    • 所以如果一个隐藏单元有着大fan-in的话,还是使用更小的权值比较好,【边多,权值小】
    • 所以当一个隐藏单元有着非常小的fan,那么就可以使用较大的权重了。 【边小,权值大】

因为权重都是随机的,所以可以通过权重的数量的平方根来作为权值的缩放尺度。

所以一个较好的原则去初始化权值的尺寸是与fan的平方根成比例的。我们同样可以用这种方法来缩放学习率

对输入的平移

在NN学习的加速问题上一个影响较大的是平移输入。也就是在输入的每个成分上增加一个常数,而且令人惊讶的是这回导致很大的不同,当使用最速梯度方法是,平移输入的值会导致非常大的不同。

通常来说平移输入的每个成分是有帮助的,也就是对所有的训练数据进行均值的话,使得他们的均值为0

假设我们有上图中的类神经元(三个圈圈的部分),只是一个线性神经元有着两个权重,并假设我们有一些训练样本。

  • 第一个训练样本是【101,101】,那么就可以得到一个输出,
  • 第二个样本是【101,99】,并用不同的颜色来对应不同的样本,

通过图中(红色和绿色线代表满足他们样本的权重拟合线)发现他们的权重差不多平行(明明交叉了好吗),如果将两者结合起来,就得到一个细长的椭圆。因为我们这里使用的是误差平方测量,沿着红线我们得到一个抛物线,

红线是这个抛物线的底部,这告诉我们在这个红色样本上得到的平方误差;

绿色也是同样道理,如果将两个抛物线加起来,就得到了一个二次碗形,在这个训练集上是一个细长的碗形,这就是误差表面的来源。

 

现在,如果将这两个样本都减去100,那么就得到了一个完全不同的误差表面,这里可以看到是一个完美的圆形,这里的绿色就是期望输出为2的权重线,考虑第一个权重乘以1,并考虑第二个权重乘以1,我们需要期望输出为2;

这条红色的线就是两个权重都相等的线,因为这里是第一个权重乘以1,第二个权重乘以-1,所以两个权重相等,这样才能得到输出(标签)为0期望值。

所以在这种情况下的误差表面就是一个完美的圆形,这上面梯度下降也是很容易的,而且我们所做的只是将它们都减去100而已。

 

如果不考虑输入,而是考虑这个输出单元,那么将他的输出单元的激活函数设置成双曲型tangents是比较有意义的,因为它的值域是(-1,1),是逻辑值域的两倍。而且更有意义的是输出单元的激活值都是粗略的0均值的,这也是的进入下一个阶段的学习更加迅速,当然这只有在双曲线tangets的输入是差不多分布在0周围的才有意义,这时候选择双曲型tangent比逻辑函数更好;但是在其他情况下逻辑函数比双曲线tangent更好。

例如:逻辑函数给你一个可以做类似将东西扫到地毯下的感觉一样,它可以给出一个输出0,那么在输入远远小于这个0的输出值的输入的时候那么输出值仍然是0,所以逻辑函数可以忽略自然输入中的一些波动。对于tangent,不得不在它能够忽略任何东西之前(这里可以看函数的曲线图)一直出现不同的输出值(这里的两者不太懂,不过记得当输入的分布不是在0周围,而是全都比如在0上的,那么还是用逻辑,这里指的是归一化后)。

对输入的缩放

另一个导致差异较大的就是对输入的缩放(之前的是平移 vs 这里的是缩放,前面是0均值 vs 这里是单位方差)。

当使用最速下降法时,对输入进行缩放是一个简单的事情,只要在整个训练集合上使得输入的成分都是单位方差就行。所以一般就有1或者-1。

这里再次考虑两个输入的神经元:

  • 观察第一个误差表面,当第一个成分很小,而第二个很大,我们得到的误差表面是一个椭圆,他有着很大的曲率,当这个大的成分对应的权值有着微小的改变的话,对输出的影响是很大的,而小成分所指示的方向的曲率很小,从而这个权值的改变很难影响误差的结果。这里的颜色指示的是我们在使用的坐标轴,而不是我们使用的训练样本(和上上图中不一样)。
  • 如果我们简单的改变输入的方差,重新缩放他们,使得第一个成分扩大10倍,第二个成分缩小10倍,那么现在就得到了一个完美的圆形误差表面。

 

【平移和缩放是非常简单的事情,但是有时候也是比较复杂的。这实际的工作使得我们能够保证得到一个圆形的误差表面从而使得工作得更好】

 

去相关的重要性

至少在线性神经元上,我们所作的就是去对输入向量的成分进行去相关,换句话说,如果考虑两个成分,并观察在整个训练集上他们之间是怎样的相关的。

考虑之前的例子,chips部分的数量和番茄酱部分的数量是如何的高度关联的(前几课中的)。我们想要试图摆脱这样的相关性。这样会让学习更加的容易,事实上有许多的方法去做这些去相关的事情,

例如PCA,是通过将最小的特征值对应的成分移出来达到维度约间的目的,(http://lvdmaaten.github.io/drtoolbox/ 这里有着完整的36种维度约间组成的matlab工具箱,其他的目测还在完善)并通过对剩下的成分除以他们各自对应的特征值的平方根来达到缩放的目的。

对于一个线性系统,这可以得到一个圆形的误差表面。一旦得到了一个圆形误差表面,这个梯度的方向就是直指最小值的,所以学习才更容易。 

 

常见问题 

上图就是人们在多层网络中常见的问题。

(1).

初始学习率很大的时候,所得到的隐藏单元就是一直激活的或者一直抑制的,

也就是说输入的权重是很大的正数,或者很大的负数,

所以他们的状态就不再依赖于输入。

也就是说来自于输出产生的误差不再影响他们了,因为他们都是位于平原(即在误差表面的平缓地带),这样导数通常是0,

所以学习会停止。

因为人们期望得到局部最小(全局最小是理想化,有时候得到局部最小也不是坏事),当学习停止,他们就会认为已经达到了局部最小,只是这时候的误差是很可怕的,所以他们得到的是个相当坏的局部最小值,通常来说这种观点是错误的。因为这通常是学习的方向一直停留在了平原并且学习终止了。

(2).

当进行分类的时候,不论使用的是平方误差还是交叉熵误差。最好的猜测策略就是正常的让输出单元等于时间比例(为1)(这里不懂什么是时间比例,和这个策略具体的意思)。

这个网络将会快速的发现这个策略,并且这个误差会下降的很快,但是具体的,当这个网络有很多层,他会在有明显的改善之前花费很长的时间

因为在基于猜测策略上的提升需要从输入中得到有意义的信息并穿过所有的隐藏层达到输出层,而当以很小的权重初始化的时候这会需要很长的时间去学习

所以如果很快速的学习,然后误差停止下降,他看上去就像找到了一个局部最小值,但是实际上这仍然是个平原。

 

在早期Hinton提到在学习的末尾需要调小学习率,但是不要太早的去调,当调小这个学习率,那么就减少了在不同mini-批量上的不同的梯度导致的随机波动。

看图中红色线,当学习突然调小的时候,我们得到了一个迅速的下降,这个错误时的我们随后学习很慢,如果我们调的太早,就不能得到绿色线的部分,在后期,就没法学习了。

 

http://blog.csdn.net/u012162613/article/details/44239919 中涉及的几个知识点:

主要是一阶的梯度法,包括SGD, Momentum, Nesterov Momentum, AdaGrad, RMSProp, Adam。 

其中SGD,Momentum,Nesterov Momentum是手动指定学习速率的,而后面的AdaGrad, RMSProp, Adam,就能够自动调节学习速率。

 

加速mini-批量学习

使用动量:在这方法中,我们不使用梯度去改变权重的位置,即,假设权重是误差表面上的一个球,标准梯度下降法会使这个球的位置改变,只是简单的将这个梯度乘以学习率然后通过向量的方式来改变这个球,

在动量的方法中,我们使用梯度去加速这个球,也就是说改变的是速度而不是位置,原理就在于这个球可以有动量,也就是说它记得之前的梯度。

在每个参数上使用独立的自适应学习率:在基于经验性测量中缓慢的调节学习率,这里明显的经验性测量方法就是在权重更新中这个改变的梯度的方向是否一样,或者说这个 梯度保持振荡才使得梯度的方向也一直在变,

    • 如果这个梯度的方向一直在变,我们所要作的就是减小学习率
    • 如果方向不变,那么就加大学习率

rmsprop:Hinton称这个方法为rmsprop,在这个方法中是通过一个权重的学习率除以这个权重近似梯度的大小的连续(这里running是翻译成连续还是运行,不知道)平均值,所以

如果梯度很大,那么除数就很大;

如果梯度很小,那么除数就很小,

这在一个较大范围内不同梯度上处理会很nice。这实际上是使用了梯度的方向的迷你批量版本,借鉴于全批量学习上被称之为 R prompt方法。

全批量学习,并使用一个梦幻的方法去考虑曲率。试图将这种方法去适应NN;或者去适应mini-批量。(Hinton这个坑挖了是不打算在这个课程中填了)。

 

然后,开始对各个问题展开讨论:(这章节 真难!)

 

1、动量方法

这部分说的是如何在NN中计算梯度下降的时候使用动量来提升学习速度。这个动量的方法可以应用于全批量学习,但是也可以用于mini-批量学习,其实他的应用范围很广的,一般在大NN上学习的最常用的组合技能:随机梯度下降法+动量+mini-批量

添加黏性 ( viscosity )

很显然,我们最后还是希望在这个误差表面能够得到一个低点,也就是丢弃能量(也就是能量最小化,参考物理中的一些重力势能,动能等模型),所以我们需要引入一些粘性(viscosity),也就是说使得在每次更新上让他的速度能够缓慢的下降消失。动量方法所要做的,就是让在高曲率方向上的振荡进行衰减。

 

动量方法的行为也是相当直观的。在误差表面上,这个球最后会稳定在某个速度上,这个速度是用动量项来使得梯度在其他方向上的速度不断的衰减,直到达到一个稳定的状态(参考上上图中的运动轨迹)。

如果这个动量项接近于1,那么就会比 普通的梯度下降法的下降速度更快,所以这个最终的速度,就是梯度乘以学习率,再1/(1-alpha)与其相乘,所以如果alpha等于0.99,那么就比只使用学习率快上100倍。

但是也需要小心的设置动量,在学习的开始,如果初始化的权值很大,那么就会有个很大的梯度,那么就得到了一群不适用于所要作的任务的权重集合,这显然这时候需要做的就是不要设置一个大动量

因为你想事情朝着好方向上快速的变化,然后用手边的问题(任务)去拟合对于不同的权重的相对正确的值,

所以就能得到一些有意义的特征提取器。所以在训练的开始,

  • 还是采用一个较小的动量,一般0.5比0 好,因为0.5可以均化一些坡和凹谷。一旦大梯度消失了,程序也运行到正常的学习阶段了,那么就是陷入了一个峡谷了,这时候就会想要沿着峡谷的方向下降,而不是左右摇晃,这时候可以缓缓的将动量值提升到最终值,或者每一步就提升一次,但是这又会开始震荡了;
  • 那么你会想,为什么不只用一个较大的值(动量大而不变),但是结果是:
    • 使用一个较小的学习率和一个大的动量会使得结果,比之前没有动量只有学习率的时候所能达到的学习率还大的情况下,还坏的结果,
    • 如果只是用一个很大的学习率,那么就会得到一个发散振荡来横穿这个山谷(意思就是不好)。

 

就在不久之前,Ilya Sutskever发现一个更好的设置动量的方法。标准的动量方法是:

    • 首先通过在当前位置上计算梯度
    • 然后考虑存储于球中速度上之前梯度的记忆,
    • 然后就可以结合之前的梯度在当前的梯度方向上做一个大跳跃(这就是加速梯度方向上的移动)。

Ilya Sutskever发现在很多情况下用Nesterov(试图优化凸函数的男人)所推荐的动量形式可以使效果更好,就是先在之前累计的梯度上做一个大跳跃,然后测量这个梯度的末尾,然后加以修正。

看上去与之前的极其的相似,所以需要自己手动画图来加以区别。一种较好的观察到底发生了什么的方法是:

在标准动量方法中,首先是加上当前的梯度,然后在这个大跳跃上加个赌注(不知道是字幕错误还是什么,反正这里的意思就是以前的方法就是上上图中介绍的方法);

而在Nesterov方法中,在基于之前累计的梯度上加上一个大的跳跃,然后在新的地方加以修正成正确的方向。(按照ppt意思,所谓的跳跃就是【alpha×上一个权重】,而梯度就是当前梯度。)

 

Nesterov方法

上图就是Nesterov方法的过程,

首先进行一个大跳跃,然后做一个修正。

第一个棕色的线就是在累计的梯度上的一跳跃,所以这个方向是依赖于在之前的迭代中我们累计的梯度的,按照这个方向进行下山。

然后进行一个修正(第一个红色线),并得到一个新的梯度方向(第一个绿线),

然后以这个作为新的累计梯度,

然后在此新的累计梯度上乘以一个数值(0.9或者0.99),然后做个新的跳跃(第二条棕色的线),然后在这个梯度的末端进行测量,并做下山操作(就是第二个红色的修正线),并得到第二个新的累计梯度(第二条绿线)。

如果现在与标准动量方法做比较,这个标准动量方法先和之前的一样以第一个棕色线(之前的累计梯度)开始,

然后进行测量当前的位置的梯度,

然后加到之前的棕色线上,这就像是做了一个大跳跃一样(第二条蓝色线),也就是初始的棕色线加上当前的梯度。

结果证明如果打算下赌注,那么先下赌注,然后修改比先修改然后下赌注要好。

 

2、关于每个连接的独立且自适应的学习率

这里的方法是有Robbie Jacobs与1980年代提出的方法,并指挥被一些人改进了。原理是:NN中的每个连接都应该有自己独立的学习率

这是靠我们观察当我们更新这个链接上的权重的时候会发生的事情来进行经验性设置的,如果这个梯度保持不变(方向不变),那么就将学习率调大,如果权重会使得梯度方向相反,那么就调小学习率。

首先考虑个问题:为什么在每个连接上有独立的自适应学习率是个好想法。在多层网络中,学习率可以在不同的权重之间有着较为广泛的变化,特别是在不同层上的权重之间。

例如:当初始化的权值很小的时候,可能会造成在第一层中的梯度远小于后面层的梯度;

另一个导致不同的权重有不同的学习率的因子是单元的,这个fan-in 【有更多输入连接(fan_in)的单位】决定着当为了修复同样的误差而同时改变不同的传入权重所造成的过度影响的尺度,

也许单元本来没有足够的输入,当为了修复这个误差而同时改变这些权重导致现在得到了过多的输入。

显然,如果有着更大的fan-in,那么就会有更大的影响,所以上图中右侧的网络模型中,两层都有着相同的fan-in(即三个绿点,三个红点),但是在许多网络中却是非常不同的。

所以想法就是:

  • 通过手动设定的全局学习率,
  • 然后再用它乘以每个权重经验性决定的合适的局部增益。

如何决定局部增益

一个简单的方法去决定这些局部增益是:首先每个权重都有个局部增益,初始化都为1,所以改变权值Wij是通过学习率乘以对应的局部增益gi,再j乘以这个权重的误差梯度,然后我们所要作的就是去调整gij。当权重的梯度没有改变符号的时候就加大gij的值,这里我们使用的是小型的额外增加(就是一点点的往上加)和乘法减小(mini-批量)(上图右下部分)。所以如果 t 时刻的权重梯度有着与 t-1 时刻相同符号的权重(这里 t 表示权重更新),然后当进行乘积后,它就是正的(上图右下的 if ),所以当得到两个负的梯度或者正的梯度,那么所要作的就是用小的额外的数值来增加gij(上图中用的是0.05);如果梯度有着相反的符号,我们所要做的就是减小gij,当giji很大的时候,我们就想要快速的减小gij,通过采用乘以一个小于1的值来进行减小(上图中是0.95)。这确保了当开始震荡的时候,大的局部增益可以快速的衰减。

还有个有趣的问题是如果这些梯度全部都是随机的那么会发生什么事情。所以在每个权重的更新上,提取一个随机梯度,然后就得到了增长的数目等于下降的数目,因为与之前的梯度一样的符号或者相反的符号的数目也差不多相等,所以会得到一群额外的0.05的增长和乘法0.95的下降,当局部是1的时候他们就会有个平衡点。因为如果这个局部增益比 1 大,通过0.95的乘法降低的数值比增加额外的0.05要多,如果局部增益比1 小,增加0.05的增长会比0.95的乘法减少的值要多。所以,在随机梯度下,我们会在 1 周围盘旋。如果梯度一直有着同样的方向,我们就能得到比 1 大的值。如果梯度一直是相反方向的,这就意味着我们在一个山谷上振荡,我们就能得到一个 比1小的值。

上图是一些让自适应学习率更好的工作的技巧,限制增益的尺度是很重要的,一个合理的范围是【0.1 10】或者【0.01 100】.不希望这个增益变得很大是因为:

这样会变得不稳定,而且也不会足够快速下降,那么就会毁了这些权重。

这个自适应学习率方法是为了全批量学习设计的,但是也能将它应用到mini批量上,但是他们还是在较大的mini批量上工作的更好(这里应该指的是每个批量的大小,而不是批量的数量),这可以确保这些梯度符号的改变不是因为mini-批量的错误采样而导致的,而是因为跑到了山谷的另一头而已。【为大样本设计】

 

可以将自适应学习率与动量结合起来,所以Jacobs建议是,不使用基于当前梯度和之前梯度之间的符号的协议,而是使用当前梯度和这个权重的速度之间的符号协议。这样做就能将动量的优势与自适应学习率的优势结合起来了。

所以,自适应学习率只处理轴对齐(axis-aligned)的影响;

然而,动量不关心轴对齐问题,动量能够处理这些对角椭圆并让方向能够快速的调整到对角方向,而这是自适应学习率做不到的。

  

3、rmsprop:用最近大小的连续平均值来划分梯度(即梯度除以这个连续平均值)

本部分首先介绍 rprop,这是用于全批量学习的,类似于Robbie Jacobs方法,不过还是不一样的。

后面会介绍如何将它改成适合mini-批量学习的,这样就保留了rprop的优势,同样也保留了mini-批量的优势(适合用来作为大的高度冗余数据集的学习),这个方法被称之为RMS Prop,是Hinton当前最喜欢的方法,用来作为一个基本的方法去对有着大冗余数据集的大NN来进行权重的学习。

这里先通过如何处理梯度的不同量纲(magnitude),因为有些梯度可以很小,而有些梯度又可以很大,这使得很难去找到一个合适的全局学习率。如果我们采用的全批量学习,我们就能在通过使用梯度的符号来处理梯度中这个大变量,这使得所有的权重都是以相同的尺寸更新的。例如:用很小的梯度来逃离平原(之前的球的模型,希望掉到最大的坑里面),这是一个很好的技巧,因为就算是小梯度也能往前迈很大的一步(跳跃),不能只是通过把学习率调大来达到这样的结果,因为这样会导致这个梯度不是很大,而是特别大。

Rprop是通过将梯度符号的想法和每个权重的自适应步长尺寸想法结合起来。所以看这个权重改变了多少,不需要去观察这个梯度量纲(大小,尺寸),只需要观察梯度的符号就好,但是还是需要观察围绕这个权重的步长尺寸,这个步长尺寸是基于时间自适应调节的。这里先撇开观察梯度的量纲,如果最近两个的梯度符号是一致的,那么就增长这个步长尺寸通过乘以一个值,例如1.2,这像是Robbie Jacob的自适应权重方法;如果最近的两个梯度符号不同,我们就降低这个步长尺寸,这时候差不多惩罚的比上升的严重,乘以0.5。而且需要限制步长尺寸,Mike Shuster的建议是将它们限制到小于50或者大于1百万(个人:这么大?)这取决于你的具体问题,例如如果有着许多很小的输入,那么就可能需要很大的权重才能产生一个有明显的影响;但是如果不是这类的问题,那么还是将权重的变化上限定在50比较好。

所以 为什么这个rprop方法不能适用于mini-批量呢?

人们有尝试过,但是发现不咋地,可以当mini-批量很大(一个批量的大小,而不是批量的数量)的时候让他很好的工作,这时候需要在步长尺寸上使用更多的保守的变化,但是这是很难的(大意就是mini-批量得大,而且每个步长还得更多的变化操作)。所以为什么不工作的原因是他违反了随机梯度下降的中心思想(即当有着小的学习率的时候,他会在基于连续的mini-批量上进行均值化梯度),所以假设我们在前9个mini批量上得到了9个梯度0.1,而在第10个mini-批量上得到了-0.9的梯度,我们一般是认为这些梯度会粗略的平均,然后差不多待在它原来的地方。

rprop不会如上述这样,rprop会以当前的梯度尺寸增强9次,而只减量一次,这就会使得权重变得很大(这里我们假设步长尺寸的自适应比mini-批量的时间尺度(time-scale)要慢)。问题就是我们能只通过使用梯度的符号来将rprop的鲁棒性与mini-批量的高效性结合起来吗,这里通过将mini-批量的梯度进行均值化才是结合梯度的正确方法,称之为RMSprop.

RMSprop就是针对mini-批量的rprop版本。

rprop就是使用梯度,但是通常被梯度的量纲(magnitude)划分,在mini-批量上的问题就是我们在划分这个梯度的时候用的是每个mini-批量的不同的量纲。所以想法就是将每个近邻的mini-批量的量纲弄成一样的,通过对每个权重的平方梯度做个移动式的均分。

所以均值平方(w,t)就是在时刻 t 的时候权值 w 移动的均值,这里时间是权重更新的索引。时间是随着每次权重更新而增长的,这里的0.9和0.1只是个例子,不过也是个合理的例子。也就是用上一个时刻的均值平方乘以0.9加上0.1乘以当前时刻上权值的梯度平方的值。然后进行求平方根,这也就是为什么称之为RMS(个人:root mean square?)的原因,通过将梯度除以这个RMS然后照例进行更新。这是的学习效果更好。注意到这里不是针对每个连接有着独立的学习率,而是一个更简单的方法,对于每个连接,有着一个不断运行的平方根均值平方梯度(RMS)的均值,然后用梯度除以它罢了。

上图是建立在rmsprop上的一些发展:

1、将rmsprop与标准动量结合起来,Hinton到目前为止的实验建议是,这样的结合体现不出动量的优势,需要更多的研究才行。

2、将rmsprop与Nesterov动量结合起来,先做一个跳跃操作,然后在做一个修正,Ilya Sutskever已经试过了并得到了很好的效果,他发现当将最近的梯度的rms用于划分修改后的项而不是这个大跳跃项的时候效果最好。

3、rmsprop和每个连接上的自适应学习率进行结合,这看上去更像rprop,这部分需要更多的研究,Hinton现在还不知道他们会变得多有帮助。

4、其他的方法,YannLeCun的团队发表的《No More Pesky Learning Rates》中有提到,其中的一些项看上去像rmsprop,但是他还拥有其他的项。Hinton认为他们提出的复杂的方法中最有优势的地方在于很像rmsprop,不过这得仔细瞧瞧。

 

上图就是在NN上学习的一些总结:

  • 一个数据集,比如1w个样本或者更少,或者一个没有冗余的大数据集,那就可以考虑全批量学习

优化方法:全批量学习可以使用例如cg或者lbfgs或者LevenbergMarkhart这样的非线性优化方法。

使用这些方法的一个优势在于他们通常都在一个工具包中,而且当需要在论文中说明的时候,只需要说我用的就是这个工具包,不需要证明所有的不同的决定;

或者可以使用自适应学习率(第四部分),这本质上是全批量方法但是是基于NN上提出的。

  • 一个大的冗余的数据集,那么一般都是使用mini-批量方法

(1) 首先要做的就是使用"动量 + 标准梯度下降法" + 可以考虑“全局学习率”,并写一个小循环去基于是否梯度有改变符号来适应这个全局学习率(就是先自己写个小部分测试下采用的这个学习率是否合理)

(但是在开始的时候,不要想采用每个独立的权重都有独立的学习率这种方法,先从易到难,不要一来就用这个);

(2) 下一步就是try下 RMS prop,当不使用动量的情况下RMS prop还是挺容易执行的,而且Hinton目前的经验表明效果也不输于带有动量的梯度下降法,而且更好。

或者可以考虑所有的有关提升rmsprop的方法,例如:加入动量或者每个独立权重的自适应学习率,但是这些仍然是未知的领域(Hinton在这方面没做多少工作,所以这里是个创新点的好地方);

最好可能发现Yann LeCun最近发的论文并去尝试过,Hinton给yann Lecun的评价是:他可能是尝试过最多种不同的随机梯度方法的并且效果还不错的人,所以值得跟进他的工作。

【Yann Lecun应该写本归纳实验经验的著作】

 

那么可能会问,为什么没有简单的配方?我们已经在NN周围转了很久,包括DNN,到目前差不多有25年了,你可能会认为Hinton他们可以提出一个通用的方法去学习。

下面列出两个原因,为什么没有简单的配方

  • 首先,nn有很多不同的种类,非常深的网络,特别是那些有着瓶颈(narrow bottleneck)的网络,Hinton后面会介绍,这些网络非常难优化而且需要的方法还是要对非常小的梯度有着高度敏感性(sensitive)的。
  • 递归网络(recurrent)是另一种情况,如果想要这种网络能够识别到过去很久前发生的事情并基于很长一段时间前发生的事情上来更新权重,他们通常很难优化;
  • 还有很多浅层网络,他们都有着不同的支持度和在很多实践中被广泛的使用,他们通常可以用不是非常精确的方法来优化,因为可以通过早点停止优化训练来解决过拟合问题。

所以面对这些不同的网络,都有着不同的方法去适应。

 

另一个原因是任务也千花百样,许多人物需要非常精确的权值,许多任务却根本不需要多精确;同样有些任务有着杂乱的属性,比如就像输入是单词一样,有些生僻单词只以0.00001的概率出现;而且当输入是像素的时候,有着非常多不同的情况出现。所以没法一刀切似的去对所有的网络进行训练。我们有着一群不同规则,但是还是不能满足,不过只要从中总结出哪些方法可以让效率更好,那么就足够了。

 


  

From: https://www.leiphone.com/news/201701/gOwAU7YFQkJcFkVB.html 

本文为印度深度学习专家、创业者 Rishabh Shukla 在 GitHub 上发表的长博文,总结了他过去的开发经验,旨在给新入门的开发者提供指导。雷锋网做了不改变原意的编译。

在深度学习领域,为了高效训练深度神经网络,有些实践方法被过来人强烈推荐。

在这篇博文中,我会覆盖几种最常使用的实践方法,从高品质训练数据的重要性、超参数(hyperparameters)到更快创建 DNN(深度神经网络) 原型模型的一般性建议。这些推荐方法中的大多数,已被学术界的研究所证实,并在论文中展示了相关实验、数学证据,比如 Efficient BackProp(Yann LeCun et al.) 和 Practical Recommendations for Deep Architectures(Yoshua Bengio)

1. 训练数据

许多 ML 开发者习惯把原始训练数据直接扔给 DNN——为什么不这么做呢?既然任何 DNN (大多数人的假设)仍然能够给出不错的结果,不是吗?但是,有句老话叫“给定恰当的数据类型,一个简单的模型能比复杂 DNN 提供更好、更快的结果”。虽然这有一些例外,但在今天,这句话仍然没有过时。因此,不管你是在计算机视觉( CV),自然语言处理(NLP)还是统计建模(Statistical Modelling)等领域,想要对原始数据预处理,有几个方法可以得到更好的训练数据:

    • 获取越大的数据库越好。DNN 对数据很饥渴,越多越好。

    • 去除所有包含损坏数据的训练样本,比如短文字,高度扭曲的图像,假输出标签,包含许多虚值(null values)的属性。

    • Data Augmentation(数据扩张)——生成新样例。以图像为例,重新调节,增加噪声等等。

2. 选择恰当的激励函数(activation function)

激励函数是所有神经网络的核心部分之一。

激励函数把渴望已久的非线性(non-linearity)加入了模型。多年来,Sigmoid 函数 一直是多数人倾向的选择。但是,Sigmoid 函数不可避免地存在两个缺陷:

(1). 尾部  sigmoids 的饱和,进一步导致梯度消失。

(2). 不以 0 为中心(输出在 0 到 1 之间)。

一个更好的替代选择是 Tanh 函数

数学上来说,Tanh 只是调整、平移过的 Sigmoid 函数:tanh(x) = 2*sigmoid(x) - 1。

虽然 Tanh 仍旧存在梯度消失的缺陷,但好消息是:Tanh 以 0 为中心。因此,把 Tanh 作为激励函数能更快地收敛(converge)。我发现使用 Tanh 通常比 Sigmoid 效果更好。

你还可以探索其他选择,比如 ReLU, SoftSign 等等。对于一些特定任务, 它们能够改善上述问题。

3. 隐藏单元和隐层(Hidden Units and Layers)的数量

保留超出最优数量的隐藏单元,一般是比较保险的做法。

这是因为任何正则化方法( regularization method)都会处理好超出的单元,至少在某种程度上是这样。

在另一方面,保留比最优数量更少的隐藏单元,会导致更高的模型欠拟合(underfitting)几率。

另外,当采用无监督预训练的表示时(unsupervised pre-trained representations,下文会做进一步解释),隐藏单元的最优数目一般会变得更大。

因此,预训练的表示可能会包含许多不相关信息(对于特定任务)。通过增加隐藏单元的数目,模型会得到所需的灵活性,以在预训练表示中过滤出最合适的信息。

选择隐层的最优数目比较直接。正如 Yoshua Bengio 在  Quora 中提到的:

“你只需不停增加层,直到测试误差不再减少。”

4. 权重初始化 (Weight Initialization)

永远用小的随机数字初始化权重,以打破不同单元间的对称性(symmetry)。

但权重应该是多小呢?推荐的上限是多少?用什么概率分布产生随机数字?

当使用 Sigmoid 激励函数时:

  • 如果权重初始化为很大的数字,那么 sigmoid 会饱和(尾部区域),导致死神经元(dead neurons)。
  • 如果权重特别小,梯度也会很小。

因此,最好是在中间区域选择权重,比如说那些围绕平均值均衡分布的数值。

幸运的是,已经有许多关于初始权重合适取值的研究。这对于高效的收敛非常重要。为初始化均衡分布的权重,均匀分布(uniform distribution )或许是最好的选择之一。

另外,就像论文中所展示的(Glorot and Bengio, 2010),有更多输入连接(fan_in)的单位,应该有相对更小的权重。

多亏这些十分透彻的试验,现在我们已经有了经过检验的公式,可以直接用来权重的初始化:

比如说在  ~ Uniform(-r, r) 提取的权重,

  • 对于 tanh 激励  r=sqrt(6/(fan_in+fan_out));
  • 对于 sigmoid 激励 r=4*(sqrt(6/fan_in+fan_out)) 。
  • fan_in 是上一层的大小, 而 fan_out 是下一层的。

5. 学习率

这或许是最重要的超参数之一,调节着学习过程。

    • 如果学习率设置得太小,你的模型很可能需要 n 年来收敛。
    • 设置得太大,再加上不多的初始训练样本,你的损失可能会极高。

一般来说,0.01 的学习率比较保险。【但这不是一个严格的标准,最优学习率与特定任务的属性息息相关】

 

相比固定学习率,在每个周期、或每几千个样例后逐渐降低学习率是另一个选择。

虽然这能更快地训练,但需要人工决定新的学习率。一般来说,学习率可以在每个周期后减半。几年前,这种策略十分普遍。

幸运的是,我们现在有了更好的、基于动能(momentum based)的方法,来调整学习率。这取决于误差函数的曲率。

 

另外,既然有些参数有更快、或更慢的学习速率;它或许能帮助我们针对模型中的单独参数,设定不同的学习率。

最近有大量关于优化方法的研究,导致了自适应学习率(adaptive learning rates)。目前我们有许多选择,从老式动能方法( Momentum Method ),到  Adagrad、Adam (个人最爱)、 RMSProp 等等。;

类似于 Adagrad 或 Adam 的方法,能替我们省去人工选择初始学习率的麻烦;

给定合适的时间,模型会开始平滑地收敛。

当然,选择一个特别合适的初始学习率仍然能起到帮助作用。

6. 超参数调参:扔掉网格搜索,拥抱随机搜索

网格搜索(Grid Search )在经典机器学习中十分普遍。但它在寻找 DNN 的最优超参数方面一点也不高效。这主要是由于 DNN 尝试不同超参数组合所耗费的时间。随着超参数不断增长,网格搜索需要的计算性能会指数级增长

有两种解决办法:

    1. 取决于你之前的经验,你可以人工对部分常见超参数调参,比如学习率、隐层数目。

    2. 采用随机搜索(random search),或者随机采样代替网格搜索,来选择最优超参数。

超参数组合通常在期望范围之内、从均匀分布中被选择出来。加入之前获得的知识来进一步缩小搜寻空间,也是有可能的(比如,学习率不应该太大也不应该太小)。大家发现,随机搜索比网格搜索高效地多。

7. 学习方法

随机梯度下降( Stochastic Gradient Descent )的老方法也许对于 DNN 不是那么有效率(有例外)。

最近,有许多研究聚焦于开发更灵活的优化算法,比如 Adagrad、Adam,、AdaDelta,、RMSProp 等等。【控制了梯度下降的步长】

在提供自适应学习率之外,这些复杂的方法还对于模型的不同参数使用不同的学习率,通常能有更平滑的收敛。把这些当做超参数是件好事,你应该每次都在训练数据的子集上试试它们。

8. 权重的维度保持为 2 的幂

即便是运行最先进的深度学习模型,使用最新、最强大的计算硬件,内存管理仍然在字节(byte)级别上进行。

所以,把参数保持在 64, 128, 512, 1024 等 2 的次方永远是件好事。这也许能帮助分割矩阵和权重,导致学习效率的提升。当用 GPU 运算,这变得更明显。

9. 无监督预训练(Unsupervised Pretraining )

不管你进行的是 NLP(自然语言处理)、计算机视觉还是语音识别等任务,无监督预训练永远能帮助你训练监督、或其他无监督模型:NLP 中词向量就(Word Vectors)无所不在;

  • 你可以用 ImageNet 的数据库,使用无监督方式对你的模型预训练,
  • 或是对于两个类别的监督分类;
  • 或是更大频域的音频样本,来在扬声器消崎模型(speaker disambiguation model)中使用该信息。

10. Mini-Batch(小批量) 对比随机学习(Stochastic Learning)

训练一个模型的主要目的是学习合适的参数,即产生输入到输出的最优映射。这些参数利用每个训练样本进行调参,不管你决定使用 batch, mini-batch 还是随机学习

当采用随机学习方法时,学习每个训练样本后权重的梯度都会进行调参,向梯度加入噪音(随机学习中“随机”的由来)。这样做的结果十分理想,比如说,训练中加入的噪音使得模型更不容易过拟合

但是,随机学习方法也许效率不高。如今的计算设备有非常可观的运算能力,随机学习很可能会浪费其中的一大部分。如果我们能计算矩阵相乘,那么为什么要限制自己,重复单个矢量组之间的乘法呢?因此,为了更高的吞吐率和更快的学习,我推荐使用 mini-batch 而不是随机学习。

但是,选择适当的 batch 规模同样重要。所以我们能保留一些噪音(相比大规模 batch),与此同时更高效地利用计算性能。一般来说,包含  16 个到 128 个样例的 batch(2 的幂)是不错的选择。通常,一旦你发现了更重要的超参数(通过随机搜索或是人工搜索),batch 规模就会确性下来。但是,有些场景中模型得到训练数据流(比如网络学习),那么采用随机学习就是不错的选择。

11. 打乱训练样本

这来自于信息理论(Information Theory)——“学习到一件不太可能发生的事却发生了,比学习一件很可能发生的事已经发生,包含更多的信息。”

同样的,把训练样例的顺序随机化(在不同周期,或者 mini-batch),会导致更快的收敛。如果模型看到的很多样例不在同一种顺序下,运算速度会有小幅提升。

12. 使用 Dropout 正则化

如果有数百万的参数需要学习,正则化就是避免 DNN 过拟合的必须手段。你也可以继续使用 L1/L2 正则化,但 Dropout 是检查 DNN 过拟合的更好方式(雷锋网按:Dropout 是指随机让网络某些隐层节点的权重不工作,不工作的那些节点可以暂时认为不是网络结构的一部分,但是它的权重会保留下来)。

执行 Dropout 很容易,并且通常能带来更快地学习。0.5 的默认值是一个不错的选择,当然,这取决于具体任务。如果模型不太复杂,0.2 的 Dropout 值或许就够了。

在测试阶段,Dropout 应该被关闭,权重要调整到相应大小。只要对一个模型进行 Dropout 正则化,多一点训练时间,误差一定会降低。

13. 周期 / 训练迭代次数

“对深度学习模型进行多个周期的训练,会得到更好的模型”——我们经常听到这句话。但多少周期才是“多”呢?其实,这里有一个简单的策略:继续按照一个固定的样例数或者周期训练模型,比如两万个样例或者一个周期。在每批样例之后,比较测试误差(test error)和训练误差(train error),如果它们的差距在缩小,那么继续训练。另外,记得在每批训练之后,保存模型的参数,所以训练好之后你可以从多个模型中做选择。

14. 可视化

训练深度学习模型有上千种出差错的方式。我猜大家都遇到过这样的场景:模型已经训练了几个小时或者好几天,然而在训练完成之后,才意识到某个地方出问题了。为了不让你自己神经错乱,一定要对训练过程作可视化处理

比较显而易见的措施是保存或打印损失值、训练误差、测试误差等项目的日志。

在此之外,一个很好的措施是采用可视化库(visualization library ),在几个训练样例之后、或者周期之间,生成权重柱状图。这或许能帮助我们追踪深度学习模型中的一些常见问题,比如梯度消失与梯度爆发(Exploding Gradient)。

15. 使用支持 GPU 和自动微分法 (Automatic Differentiation)的库

谢天谢地,对于快速创建原型模型,我们已经有了相当不错的库,比如 Theano, Tensorflow, Keras 等等。几乎所有这些深度学习库支持 GPU 计算和自动微分法。所以,你不需要深入研究核心 GPU 编程技术(除非你想——这绝对很有意思)。你也不需要写自己的微分代码——在非常复杂的模型上这相当费劲(但若需要,你应该有能力去做)。 Tensorflow还提供了分布式计算的支持——如果你是土豪的话。


其他一些概念,比如 Normalization of inputs, Batch/Layer Normalization, Gradient Check 等。

 

posted @ 2017-07-14 16:14  郝壹贰叁  阅读(685)  评论(0编辑  收藏  举报