如果一个神经网络模型中,我们把学习效率 learning rate 总是调的很低,理论上只要时间允许的情况下,结果也总是可以达到预期的。但是现实很骨感,在迅速变迁的时代,学得不够快的模型又怎么能够满足以效率著称的科技公司们的胃口呢?因此必须有一个更好的办法加速这个学习过程,更快的找到 Hyperparameter 才行。
虽然前面说的 Gradient Descent 理论上很完美,总是沿着梯度不断下滑,到最后就可以找到最小值,但是实际过程中越多维度越容易造成的坑坑巴巴路面总是让 GD 的路径扭来扭去,不直接快速的滑到低谷里,因此這邊即将介紹一些方法来改进这个缺陷。
最简单的 GD 长相如下
>>> while True:
weight_grad = evaluate_gradient(loss_fun, data, weights)
weights += -step_size * weight_grad # perform parameter update
就如同前面一个章节提到的,如果没有好的 normalization 过程,那么在不同权重影响力偏差的情况下,再加上每次采样都是 mini-batch 的方式只有局部数据的支持,就更容易走出歪歪斜斜的轨迹出来,如图:
这只是一个二维的路径波动,红点表示 GD 的出发点,红线表示波折的路径,如果再把维度增加,那么整个轨迹将会变得更加的混乱耗时,并且将出现更多可以被误认为最小值的洼地。
另一个问题是,图里面虽然单纯的显示了一个最低点(笑脸),但是实际情况可能是有各种各样的坑洞与 “当个区域” 的最小值,甚至只是遇到了一个平原区域刚好没有梯度,这些情况都不是整个方程式的最小值,如果初始位置放得不对,红点将只能够沿着梯度滑到 local minimum 而永远卡死在 “该坑” 里面万劫不复超生。
为了解决上述问题,原本的算法是专注在 “步数” 方面随着梯度大小的增加与减少,取而代之的是使用速度的概念,根据当下给定的梯度值去预测未来(下一步)的速度该是如何前进的,由于速度有方向性,因此可以一起把方向和大小同时掌握在计算过程中,如图:
对比于纯粹的 SGD 方法,Momentum 项可以视为是当前速度的 friction 摩擦力(修正方向与量的概念),藉由控制整个速度向量的步进,原本歪七扭八的路线就会得到很好的平滑修正,虽然可能已经抵达了极值点的时候还是会因为一个惯性继续前行,后面几步再渐渐修正回极值点的位置上,但找极值的速度相比起来也还是可以更加有效率。
这个方法其实跟上一个一样,都是 Momentum 系列的概念,唯一差别就是向量加法上的不同,如图:
Normal(左)的做法是在当下的那一点基于先前梯度预测出来的速度,加上当下该点实际上的梯度,去加总出一个下一步的修正方向;反之 Nesterov(右)不同的地方在于它所加的梯度值是基于当下点预测未来 “一步” 会到达的那个新点的梯度,相加后得出下一步的修正方向。具体算法与代码如下:
其实这两个方法的出发点是类似的,所以结果上来看也没有什么太多的不同,差不多的效率。
一般来说,我们并不希望看到非常陡峭的最小值出现,因为在实际应用中它可能就是一个过拟合的解,甚至可能等之后加入更多的数据一同训练时,这个点就被平均掉了,flat minimum would be more robust!
这是一个现在任职 Stanford 的教授它博士的时候提出的算法,特点在于每次从梯度给予步进方向和量的时候,总要除以历史记录中所有梯度平方的总和的开根号值,目的在于处理那些权重影响力不同的点的步进方向,给其中影响力大的权重除以相对大的值,和影响力小的权重除以相对小的值,就可以有效的消除 normalization 没弄好的误差。如图公式:
要是走的步数越来越多了,分母项的加总项也会越来越大,计算的东西越来越多的同时,还降低了每次行走的步距,并且它不适合 “平原行走” ,会直接停在原地,只适用 Convex 地形,因此 RMSProp 就出来解救危难了。
如上图的公式表示,它不像 AG 那样总是拖着沉重的历史包袱行走于梯度降低的路上,他学会了 “淡忘” 历史信息,加了一个 decay_rate 项于其中。This small modification ended up like a momentum update except we are having a momentum square gradient rather than the momentum actual gradient.
但是为了要让同一个方法在不同的条件中都能够最好的表现,把 learning rate 分开到不同的算式成为了必须的过程。
说了那么多好方法,何不让他们取长补短合在一起用呢?这就来了个 Adam!
下面链接是 Adam 的论文讲解:
o https://arxiv.org/pdf/1412.6980.pdf
The code goes like this:
first_moment = 0
second_moment = 0
while True:
dx = compute_gradient(x)
# here comes the method of SGD momentum
first_moment = B1 * first_moment + (1 - B1) * dx
# here comes the method of AdaGrad/RMSProp
second_moment = B2 * second_moment + (1 - B2) * dx * dx
first_unbias = first_moment / (1 - B1 ** t)
second_unbias = second_moment / (1 - B2 ** t)
# two of these codes above are used to prevent the beginning stride from too big value
x -= learning_rate * first_moment / ((np.sqrt(second_moment) + 1e-7))
如代码所描述的那样,这个方法就如同 RMSProp + Momentum,具有两者的特征,不仅保持了原本 Momentum 的冲劲,也有 RMSProp 的冷静。
不过需要注意 second_moment 的初始值,如果分母的值一开始很小,就会从数学算法上造成很大的步进(非地形梯度产生),这个情况可能让第二步跑到一个意想不到的位置,使得收敛无法控制。为此代码中添加了保护措施,如 # 标记。
Adam 是老师的 default method,并且 B1 = 0.9;B2 = 0.999;learning_rate = 1e-3 or 5e-4 通常是个好的开头!
以上所有的方法 learning_rate 都是一个 hyperparameter ,意味着最恰当的值只能靠人的经验去输入。
上面介绍的所有算法都是基于一阶的梯度计算,不过如果把一阶的梯度方程作为一个原始的方程再次寻求其梯度,好处就是可以直接一步到位梯度的最小值的位置(飞跃式),并且不需要 learning rate 这个参数的介入,公式如下:
又名为 “second-order Taylor expansion“,虽然这方法理论上很完美,但在骨感的现实面前还是一样的无力,因为当这个方法应用在 deep learning 的时候,没有那么多的计算机内存去缓冲这些待处理数据和节点。
另外,整体表现看来,这个方法并不是很稳定,所以就简单介绍到这里。
对于 local minimum 的问题,采用的方式可以是多几个测试点,从该些测试点开始做梯度运算,最后做交叉对比看谁的值最恰当。
前面的课程中介绍过 L2 的方法,然而它实际应用在 CNN 的模型中时没起到什么显著的效果,Regularization 的公式如下:
因此这边介绍一个非常非常实用且常用的方法:Dropout
Dropout
关于 dropout 的两篇论文网址如下:
o https://pdfs.semanticscholar.org/58b5/0c02dd0e688e0d1f630daf9afc1fe585be4c.pdf
o https://www.cs.toronto.edu/~hinton/absps/JMLRdropout.pdf
不像 L2 那样在每个项后面都加上一些东西,这个方法随机的把每层 neural network 设定为 0 的输出,让他们不被 activated,像这样:
dropout 成为一个 good idea 的理由:
但是 dropout 也是有缺点的,这般随机的归零会增加整个 model 运算的时间,不过为了拿到更好的结果,那是值得的。更多的代码范例请自行查阅课堂讲义。
除了 dropout 之外,尚有很多好的方法值得被运用在 nerual network 里面提升分辨效能:
站在巨人的肩膀上就是这个概念,我们可以利用别人已经训练好的庞大 neural network,经过简单的修改后定制化的为我所用。过程如下:
Here is the strategy when encountering different situations:
Very similar dataset | Very different dataset | |
---|---|---|
Very little data | 用线性分选器套在现有的 model 上即可 | 那麻烦大了,选一个像一点的 net 再尝试吧 |
Quite a lot of data | 基于已有的神经网络,增加几层新神经层把新的数据融入网络中 | 多加几层神经层,把新的数据融入其中外,整个 initialization 的过程与参数设置可能都要重新调整 |
If we are facing a problem without a corresponding dataset to train with, go to find some pre-trained dataset so that we can only change a little bit of parameters based on that what we called "model-zoo".
The list of model-zoo for those in different frameworks:
下节链接:卷积神经网络 + 机器视觉:L8_Static_Tensorflow_Dynamic_Pytorch (斯坦福课堂)