lecture6-mini批量梯度训练及三个加速的方法

Hinton的第6课,这一课中最后的那个rmsprop,关于它的资料,相对较少,差不多除了Hinton提出,没论文的样子,各位大大可以在这上面研究研究啊。


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

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


        这里的错误表面就是在一个空间中,水平轴是对应于NN的权重,竖直轴对应于所产生的错误的表面。对于一个误差平方的线性神经元,这个表面总是一个二次的碗形状。竖直交叉的部分是抛物线,水平交叉部分是椭圆形。对于多层非线性网络来说,这个错误表面更加的复杂。但是因为权重都不是很大,所以这个表面是很平滑的,并且局部的部分总是可以用一个二次碗形的部分来进行逼近,虽然有可能不是碗的底部,但是却可以用二次碗的部分块来很好的拟合局部误差表面。


如果我们观察在当误差表面是一个二次气泡(类似气球吧)的时候使用全批量学习方法的收敛速度,明显所要干的事情就是下山(讲梯度常用的例子)来减少误差,但是问题是最速下降的方向不是指向我们所希望的(上图中黑色箭头,我们希望指向绿色点的,但是按照局部梯度来说却是黑色箭头指示的方向)

我们所希望的是在红色指向绿色的方向走一大步,而不是横跨上图中的椭圆的部分,最后会使得学习时间很长,而且一直在左右动荡,而正确的梯度方向却每次只迈进一小步,这明显不符合我们的想法。也许我们会认为线性系统会遇到这样的问题,那么对于优化大的非线性网络来说呢?即使是这些非线性多层网络,这些问题也依然存在,这是一个相似的问题。因为在非线性多层网络中,这些错误表面也不是全局二次碗形的(即问题不是凸的,有着许多的局部最小存在),局部化使得他们都有相似的特性。这也就让我们倾向于认为在某些方向上他们是钩状的,而在其他方向上不是钩状(这句话意思就是参考一快地,上面有一些坑坑洼洼,还有个最大的坑,这些坑就相当于局部最小,最大的坑就是全局最小,然后还是有很多地方是平面不怎么下降的)。


所以在这种情况下加大学习率是错误的行为,因为这会导致在类似峡谷(前面的局部碗)中来回的动荡,所以会造成发散而不是收敛。我们想要的是在沿着山谷的方向上,很小但是一致的梯度方向上快速的移动,而在很大但是不一致的梯度方向上慢慢的移动(这里的模型参考上张图的椭圆形数据集),也就是说如果在很短的距离方向上(上上图中横跨椭圆的方向,黑色箭头)上梯度会来回的相反。

插播:


如果有一个高度冗余的数据集,并在前一半的数据集上计算一个权重的梯度,那么就可能发生即使在后半数据集上计算这个权重的梯度和前面得到的值是一样的。所以相比较发现在整个数据集上计算梯度是浪费时间的,更好的方法就是在数据的子集上计算梯度,然后更新权值,然后在剩下的数据上计算更新后权值的梯度,如果将这个方法发挥到极限,那么就是一个样本上计算梯度,然后更新权值,然后计算下一个样本在基于上一个样本得到的权值上的梯度。通常来说,一般不会这么极限,所以通常更好的方法是用小型mini批量,通常是10,100或者甚至1000个样本。mini批量的好处是与“online”方法相比,在更新权值上的计算量更少;另一个优势就是当计算梯度的时候,可以以并行的方式计算这一整群样本(一个mini 批量)的梯度,大多数计算机都擅长矩阵,矩阵乘法,这就能够让我们考虑一整群训练样本,并在同一时间将这个权值应用于这一整群训练样本去得到激活值 并输入给NN的下一层。矩阵乘法在GPU上可以更加的高效。

        但是在使用mini批量的时候,不希望在一个mini批量中答案总是一样的,并且不希望在下一个mini批量中有着不同的但是还是总是一样的答案(这句话没懂,但是按照下面的意思就是在考虑类别数量的时候权衡mini批量中不同类别的所占比例)。这也会导致权重会有没必要的动荡。理想情况是,如果有10类,那么设置mini批量的大小是10或者100,这样可以使得在一个mini批量中每个类别有着相同的样本量。一种能够逼近这种选择方法的方法就是先在所有样本的基础上进行随机排序,然后随机抓取mini-批量,但是需要避免在整个数据集上无特点的mini'批量,因为这时候不管怎么抓取,mini批量的包含类别都是同一类。


所以这里有两种关于NN的训练算法:全梯度算法(批量梯度),在所有的训练样本上计算梯度,基于此方法,有很多可以加速训练的方法,比如一个非线性版本的加速方法叫共轭梯度。在优化界,人们已经研究如何优化平滑的非线性函数很多年了,现在的多层NN是与他们研究的问题都有所不同的,所以在这些方法上他们提出的方法差不多都需要进行一些修改来适应这些多层NN;但是当有着一个高度冗余和大型训练集,选择mini批量梯度学习方法总是人们优先考虑的,也许mini批量会很大(就是总样本除以每个mini批量的尺寸),但是相比较而言mini批量总是更具效率。


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

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

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

        这部分介绍当使用mini批量的随机梯度下降的时候遇到的一系列问题,并一些技巧使得工作更好的执行。


第一个遇到的问题就是如何在自己的网络中进行权重等参数的初始化。如果两个隐藏单元有着一样的权值,一样的偏置,并且接受的输入都是一样的,那么就没必要区别对待,因为他们的梯度也是一样的,所以希望他们学到不同的特征检测器,那么就需要将它们区别对待。这里可以采用很小的随机权值来对权重初始化,以此来打破对称性,而且这些小的随机权重不需要相互之间有一样的尺寸。

所以如果有一个隐藏单元有着很大的fan-in(Fan-in is a term that defines the maximum number of digital inputs that a single logic gatecan 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上的,那么还是用逻辑,这里指的是归一化后)。


另一个导致差异较大的就是对输入的缩放(之前的是平移,这里的是缩放,前面是0均值,这里是单位方差)。当使用最速下降法时,对输入进行缩放是一个简单的事情,只要在整个训练集合上使得输入的成分都是单位方差就行。所以一般就有1或者-1,这里再次考虑两个输入的神经元:观察第一个误差表面,当第一个成分很小,而第二个很大,我们得到的误差表面是一个椭圆,他有着很大的曲率,当这个大的成分对应的权值有着微小的改变的话,对输出的影响是很大的,而小成分所指示的方向的曲率很小,从而这个权值的改变很难影响误差的结果。这里的颜色指示的是我们在使用的坐标轴,而不是我们使用的训练样本(和上上图中不一样)。如果我们简单的改变输入的方差,重新缩放他们,使得第一个成分扩大10倍,第二个成分缩小10倍,那么现在就得到了一个完美的圆形误差表面。

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


至少在线性神经元上,我们所作的就是去对输入向量的成分进行去相关,换句话说,如果考虑两个成分,并观察在整个训练集上他们之间是怎样的相关的。考虑之前的例子,chips部分的数量和番茄酱部分的数量是如何的高度关联的(前几课中的)。我们想要试图摆脱这样的相关性。这样会让学习更加的容易,事实上有许多的方法去做这些去相关的事情,例如PCA,是通过将最小的特征值对应的成分移出来达到维度约间(http://homepage.tudelft.nl/19j49/Matlab_Toolbox_for_Dimensionality_Reduction.html 这里有着完整的36种维度约间组成的matlab工具箱,其他的目测还在完善)的目的,并通过对剩下的成分除以他们各自对应的特征值的平方根来达到缩放的目的。对于一个线性系统,这可以得到一个圆形的误差表面。一旦得到了一个圆形误差表面,这个梯度的方向就是直指最小值的,所以学习才更容易。


上图就是人们在多层网络中常见的问题。一个是当初始学习率很大的时候,所得到的隐藏单元就是一直激活的或者一直抑制的,也就是说输入的权重是很大的正数,或者很大的负数,所以他们的状态就不再依赖于输入。也就是说来自于输出产生的误差不再影响他们了,因为他们都是位于平原(即在误差表面的平缓地带),这样导数通常是0,所以学习会停止。因为人们期望得到局部最小(全局最小是理想化,有时候得到局部最小也不是坏事),当学习停止,他们就会认为已经达到了局部最小,只是这时候的误差是很可怕的,所以他们得到的是个相当坏的局部最小值,通常来说这种观点是错误的。因为这通常是学习的方向一直停留在了平原并且学习终止了。

第二个问题就是当进行分类的时候,不论使用的是平方误差还是交叉熵误差。最好的猜测的策略就是正常的让输出单元等于时间比例(为1)(这里不懂什么是时间比例,和这个策略具体的意思)。这个网络将会快速的发现这个策略,并且这个误差会下降的很快,但是具体的,当这个网络有很多层,他会在有明显的改善之前花费很长的时间,因为在基于猜测策略上的提升需要从输入中得到有意义的信息并穿过所有的隐藏层达到输出层,而当以很小的权重初始化的时候,这会需要很长的时间去学习。所以如果很快速的学习,然后误差停止下降,他看上去就像找到了一个局部最小值,但是实际上这仍然是个平原。


在早期Hinton提到在学习的末尾需要调小学习率,但是不要太早的去调,当调小这个学习率,那么就减少了在不同mini-批量上的不同的梯度导致的随机波动。看图中红色线,当学习突然调小的时候,我们得到了一个迅速的下降,这个错误时的我们随后学习很慢,如果我们调的太早,就不能得到绿色线的部分,在后期,就没法学习了。


上图中这四种技巧可以让mini-批量学习的速度变得更快。

使用动量:在这方法中,我们不使用梯度去改变权重的位置,即,假设权重是误差表面上的一个球,标准梯度下降法会使这个球队位置改变,只是简单的将这个梯度乘以学习率然后通过向量的方式来改变这个球,在动量的方法中,我们使用梯度去加速这个球,也就是说改变的是速度而不是位置,原理就在于这个球可以有动量(这也叫解释?),也就是说它记得之前的梯度。

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

rmsprop:Hinton称这个方法为rmsprop,在这个方法中是通过一个权重的学习率除以这个权重近来梯度的大小的连续(这里running是翻译成连续还是运行,不知道)平均值,所以如果梯度很大,那么除数就很大;如果梯度很小,那么除数就很小,这在一个较大范围内不同梯度上处理会很nice。这实际上是使用了梯度的方向的迷你批量版本,借鉴于全批量学习上被称之为 R prompt方法。

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

三、动量方法

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


按照三中的假设,假设在误差表面上的一个球,这个球所在位置的水平平面表示当前的权重向量,竖直方向代表误差大小。球以静止状态开始,然后给它进行初始化,那么它就会按照最速下降的方向移动,也就是梯度方向。但是一旦它得到了某些速度,那么它就不会还沿着梯度的方向移动了。动量就是使这个球能够按照之前的方向保持移动的方法。很显然,我们最后还是希望在这个误差表面能够得到一个低点,也就是丢弃能量(也就是能量最小化,参考物理中的一些重力势能,动能等模型),所以我们需要引入一些粘性(viscosity),也就是说使得在每次更新上让他的速度能够缓慢的下降消失。动量方法所要做的,就是让在高曲率方向上的振荡进行衰减。如上图中红色起始点,并观察两步之后的绿色的点,这个点有两个梯度是差不多相等但是也方向差不多相反的,结果就是横跨这个山谷方向上的梯度被相互抵消了(物理上的受力分析),但是沿着山谷方向的梯度没有被抵消,这个方向上一直在加速,所以当动量的方法稳定下来后,他会沿着山谷的谷底方向前进,并加速这个方向上的速度,如果够幸运,还能使得相比较于使用最速下降法来说整个训练速度提升不少。


而且动量的式子公式也是相当的简单。如上图所示,这里的时刻 t 时候的速度,就是代表相对应的权重更新。时刻 t 时候的速度向量就等于之前 t-1 时候的速度减一点值,也就是将之前的速度向量乘以某个小于1的数,例如0.9,这的确有种粘性效果,不过Hinton这里称之为动量,alpha动量,然后在加上当前梯度的影响部分。也就是将 t 时刻的梯度乘以某个学习率,然后变成 t 时刻新的速度,也就是说 t 时刻的权重变化就等于 t 时刻的速度了  ,权重的变化就能够用之前的权重变化和当前的梯度来表示。(我觉得看图都比我这段绕口令来的清楚)。


 动量方法的行为也是相当直观的。在误差表面上,这个球最后会稳定在某个速度上,这个速度是用动量项来使得梯度在其他方向上的速度不断的衰减,直到达到一个稳定的状态(参考上上图中的运动轨迹)。如果这个动量项接近于1,那么就会比 普通的梯度下降法的下降速度更快,所以这个最终的速度,就是梯度乘以学习率,再1/(1-alpha)与其相乘,所以如果alpha等于0.99,那么就比只使用学习率快上100倍。

但是也需要小心的设置动量,在学习的开始,如果初始化的权值很大,那么就会有个很大的梯度,那么就得到了一群不适用于所要作的任务的权重集合,这显然这时候需要做的就是不要设置一个大动量。因为你想事情朝着好方向上快速的变化,然后用手边的问题(任务)去拟合对于不同的权重的相对正确的值,所以就能得到一些有意义的特征提取器。所以在训练的开始,还是采用一个较小的动量,一般0.5比0 好,因为0.5可以均化一些坡和凹谷。一旦大梯度消失了,程序也运行到正常的学习阶段了,那么就是陷入了一个峡谷了,这时候就会想要沿着峡谷的方向下降,而不是左右摇晃,这时候可以缓缓的将动量值提升到最终值,或者每一步就提升一次,但是这又会开始震荡了;那么你会想,为什么不只用一个较大的值(就是动量的取值较大,而且不变),但是结果是:使用一个较小的学习率和一个大的动量会使得结果,比之前没有动量只有学习率的时候所能达到的学习率还大的情况下,还坏的结果,如果只是用一个很大的学习率,那么就会得到一个发散振荡来横穿这个山谷(意思就是不好)。


就在不久之前,Ilya Sutskever发现一个更好的设置动量的方法。标准的动量方法是首先通过在当前位置上计算梯度然后考虑存储于球中速度上之前梯度的记忆,然后就可以结合之前的梯度在当前的梯度方向上做一个大跳跃(这就是加速梯度方向上的移动)。Ilya Sutskever发现在很多情况下用Nesterov(试图优化凸函数的男人)所推荐的动量形式可以使效果更好,就是先在之前累计的梯度上做一个大跳跃,然后测量这个梯度的末尾,然后加以修正。看上去与之前的极其的相似,所以需要自己手动画图来加以区别。一种较好的观察到底发生了什么的方法是:在标准动量方法中,首先是加上当前的梯度,然后在这个大跳跃上加个赌注(不知道是字幕错误还是什么,反正这里的意思就是以前的方法就是上上图中介绍的方法);而在Nesterov方法中,在基于之前累计的梯度上加上一个大的跳跃,然后在新的地方加以修正成正确的方向。(按照ppt意思,所谓的跳跃就是【alpha×上一个权重】,而梯度就是当前梯度。)


上图就是Nesterov方法的过程,首先进行一个大跳跃,然后做一个修正。第一个棕色的线就是在累计的梯度上的一跳跃,所以这个方向是依赖于在之前的迭代中我们累计的梯度的,按照这个方向进行下山。然后进行一个修正(第一个红色线),并得到一个新的梯度方向(第一个绿线),然后以这个作为新的累计梯度,然后在此新的累计梯度上乘以一个数值(0.9或者0.99),然后做个新的跳跃(第二条棕色的线),然后在这个梯度的末端进行测量,并做下山操作(就是第二个红色的修正线),并得到第二个新的累计梯度(第二条绿线)。

如果现在与标准动量方法做比较,这个标准动量方法先和之前的一样以第一个棕色线(之前的累计梯度)开始,然后进行测量当前的位置的梯度,然后加到之前的棕色线上,这就像是做了一个大跳跃一样(第二条蓝色线),也就是初始的棕色线加上当前的梯度。结果证明如果打算下赌注,那么先下赌注,然后修改比先修改然后下赌注要好。

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

这里的方法是有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)的影响;然而动量不关心轴对齐问题,动量能够处理这些对角椭圆并让方向能够快速的调整到对角方向,而这是自适应学习率做不到的。

五、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-批量方法,不用的话就是巨大的浪费了,首先要做的就是使用带有动量的标准梯度下降法,可以选择一个全局学习率,并写一个小循环去基于是否梯度有改变符号来适应这个全局学习率(就是先自己写个小部分测试下采用的这个学习率是否合理)(但是在开始的时候,不要想采用每个独立的权重都有独立的学习率这种方法,先从易到难,不要一来就用这个);下一步就是时下RMS prop,当不使用动量的情况下RMS prop还是挺容易执行的,而且Hinton目前的经验表明效果也不输于带有动量的梯度下降法,而且更好。或者可以考虑所有的有关提升rmsprop的方法例如加入动量或者每个独立权重的自适应学习率,但是这些仍然是未知的领域(Hinton在这方面没做多少工作,所以这里是个创新点的好地方);最好可能发现Yann LeCun最近发的论文并去尝试过,Hinton给yann Lecun的评价是这可能是尝试过最多种不同的随机梯度方法的并且效果还不错的人,所以值得跟进他的工作。

那么可能会问,为什么没有简单的配方?我们已经在NN周围转了很久,包括DNN,,到目前差不多有25年了,你可能会认为Hinton他们可以提出一个通用的方法去学习。下面列出两个原因,为什么没有简单的配方:首先,nn有很多不同的种类,非常深的网络,特别是那些有着瓶颈(narrow bottleneck)的网络,Hinton后面会介绍,这些网络非常难优化而且需要的方法还是要对非常小的梯度有着高度敏感性(sensitive)的。递归网络(recurrent)是另一种情况,如果想要这种网络能够识别到过去很久前发生的事情并基于很长一段时间前发生的事情上来更新权重,他们通常很难优化;还有很多浅层网络,他们都有着不同的支持度和在很多实践中被广泛的使用,他们通常可以用不是非常精确的方法来优化,因为可以通过早点停止优化训练来解决过拟合问题。所以面对这些不同的网络,都有着不同的方法去适应。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/290398.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Dapr集成之GRPC 接口

Dapr 为本地调用实现 HTTP 和 gRPC API 。通常大家第一时间想到的是通过 gRPC 调用 Dapr,更重要的一点是Dapr 也可以通过 gRPC 与应用程序通信。要做到这一点,原理很简单,应用程序需要托管一个gRPC服务器,并实现 Dapr 的GRPC 规范…

jQuery Validate验证框架详解

jQuery Validate验证框架详解 jQuery校验官网地址&#xff1a;http://bassistance.de/jquery-plugins/jquery-plugin-validation 一、导入js库 <script type"text/javascript" src"<%path %>/validate/jquery-1.6.2.min.js"></script> &…

RNN入门笔记

本笔记来源自Youtube李宏毅老师的RNN视频归纳&#xff0c;主要分为以下几个知识点: RNN 的特点RNN 的几种实现方法 (Simple RNN, LSTM)RNN 的训练不稳定性RNN 的keras实现 (定长和变长输入案例) Recurrent Neural Network Feature of RNN Differ from normal Neural Networ…

WPF 基础控件之 DatePicker 样式

此群已满340500857 &#xff0c;请加新群458041663由于微信群人数太多入群请添加小编微信号yanjinhuawechat 或 W_Feng_aiQ 邀请入群需备注WPF开发者 PS&#xff1a;有更好的方式欢迎推荐。支持NugetInstall-Package WPFDevelopers.Minimal -Version 3.2.001—代码如下一、创建…

stagefright框架(四)-Video Buffer传输流程

這篇文章將介紹Stagefright中是如何和OMX video decoder传送buffer。 (1) OMXCodec會在一開始的時候透過read函式來傳送未解碼的data給decoder&#xff0c;並且要求decoder將解碼後的data傳回來 status_t OMXCodec::read(...){ if (mInitialBufferSubmit) { mInitialBuffe…

微信支付四大支付模式分别有哪些区别?

微信支付是集成在微信客户端的支付功能&#xff0c;用户可以通过手机完成快速的支付流程。微信支付已为百货、餐厅、便利店、酒店、快递、景区、医院、售货机等提供了支付与营销的全方位支持。 目前微信支付已实现刷卡支付、扫码支付、公众号支付、APP支付&#xff0c;并提供企…

利用Deep Reinforcement Learning训练王者荣耀超强AI

Mastering Complex Control in MOBA Games with Deep Reinforcement Learning&#xff08;一&#xff09;知识背景&#xff08;二&#xff09;系统架构&#xff08;三&#xff09;算法结构3.1 Target Attention3.2 利用LSTM学习技能连招释放3.3 Decoupling of Control Dependen…

C和指针之编译出现warning: implicit declaration of function ‘matrix_multiply‘ is invalid in C99问题

1、问题 在我的mac上编译一个c文件&#xff0c;出现下面错误2、原因和解决办法 是因为我用vim的时候&#xff0c;把函数名少写了一个字符导致&#xff0c;把这个函数名改正就行了。

5. 堪比JMeter的.Net压测工具 - Crank 实战篇 - 接口以及场景压测

1. 前言通过之前的学习&#xff0c;我们已经掌握了crank的配置以及对应http基准工具bombardier、wrk、wrk2的用法&#xff0c;本篇文章介绍一下如何将其用于实战&#xff0c;在实际的项目中我们如何使用crank来完成压测任务。2. 项目背景目前有一个项目&#xff0c;我们希望通过…

Pytorch快速入门笔记

Pytorch 入门笔记1. Pytorch下载与安装2. Pytorch的使用教程2.1 Pytorch设计理念及其基本操作2.2 使用torch.nn搭建神经网络2.3 创建属于自己的Dataset和DataLoader2.3.1 编写Dataset类2.3.2 编写Transform类2.3.3 将Transform融合到Dataset中去2.3.4 编写DataLoader类2.4 使用…

详解用65行javascript代码做Flappy Bird

点击查看特效JavaScript做Flappy Bird游戏&#xff0c;代码仅仅65行资源包括&#xff1a;javascript源码&#xff1a;phaser.min.js&#xff1b;main.js&#xff1b;index.html素材&#xff1a;两张图片&#xff01;素材PS&#xff1a;素材源码下载来我的前端群570946165&#…

C和指针之数组编程练习5 (矩阵相乘)

1、问题 5.如果A是个x行y列的矩阵,B是个y行z列的矩阵,把A和B相乘,其结果将是另一个x行z列的矩阵C。这个矩阵的每个元素是由下面的公式决定的: 例如: 结果矩阵中14这个值是通过2-2加上-6-3得到的,编写一个函数,用于执行两个矩阵的乘法。函数的原型如下: void matrix_mul…

我的技术回顾因ABP框架触发DevOps云原生之路-2020年

我的技术回顾&#xff1a;2015年&#xff1a;我的技术回顾那些与ABP框架有关的故事-2015年2016年&#xff1a;从ABP框架国内社区发展回顾.NET技术变迁-2016年2017年&#xff1a;我的技术回顾那些与ABP框架有关的故事-2017年2018年&#xff1a;我的技术回顾那些与ABP框架有关的故…

半身头像

画的好丑。。。继续加油 转载于:https://www.cnblogs.com/manlurensheng/p/4102631.html

Swift - 操作SQLite数据库(引用SQLite3库)

SQLite轻量级数据库在移动应用中使用非常普遍&#xff0c;但是目前的库是C编写的&#xff0c;为了方便使用&#xff0c;对SQLite相关的操作用Swift进行了封装。这个封装代码使用了一个开源项目SQLiteDB&#xff0c;地址是&#xff1a;https://github.com/fahimf/sqlitedb 重要事…

如何在Clion中使用C++调用Python代码

在很多时候&#xff0c;我们需要在一个c工程项目中调用部分Python代码&#xff0c;这就需要我们实现Python和C之间的交互。交互方式有两种&#xff1a;1. 依靠 TCP 建立的网络通信交互&#xff1b;2. 嵌入式混合语言编程&#xff08;Embedding Code&#xff09;。这里主要介绍后…

.NET6之MiniAPI(二十四):用Polly重试

为了保障系统的稳定和安全&#xff0c;在调用三方服务时&#xff0c;可以增加重试和熔断。重试是调用一次失败后再试几试&#xff0c;避免下游服务一次闪断&#xff0c;就把整个链路终止&#xff1b;熔断是为了防止太多的次数的无效访问&#xff0c;导致系统不可知异常。Polly是…

CLion 中使用 C++ 版本的 OpenCV

配置环境&#xff1a; Windows 10CLion 2020OpenCV 3.4.1MinGW-w64 1. 下载 CLion 并配置好 MinGW CLion 下载地址&#xff1a;https://www.jetbrains.com/clion MinGW 安装包下载地址&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1c00uHbcf_jGeDDrVg99jtA 提取码&…

如何理解 C# 中的 System.Void 类型?

咨询区 ordag我知道方法声明成 void 表示不返回什么东西&#xff0c;但我发现在 C# 中 void 不仅仅是一个关键词&#xff0c;而且还是一个真实的类型。void 是 System.Void 的别名&#xff0c;就像 int 的别名是 System.Int32 一样&#xff0c;但为什么不允许直接使用Void类型呢…

获得手机的ip

本文转载至 http://blog.csdn.net/showhilllee/article/details/8746114 iosip手机貌似ASI里获取ip地址的链接不可以了。也曾试过whatismyip&#xff0c;在其网站上的截图获取的ip是正确的&#xff0c;单不知道为什么在我这里却是错误的。所以&#xff0c;在这里分享一下获得手…