首先讲讲Batch,我们实际上在算微分的时候,并不是真的对所有 Data 算出来的 L 作微分,而是把所有的Data分成一个一个的Batch,也有人叫做Mini Batch。每次在更新参数的时候,是拿出一个Batch的数据来计算Loss,算出Gradient,然后更新参数。再拿另外一个Batch大小的数据,计算Loss,再算出Gradient,再更新参数,以此类推。
所有的 Batch 看过一遍,叫做一个 Epoch。
你今天在做这些 Batch 的时候,你会做一件事情,叫做 Shuffle。Shuffle 有很多不同的做法,但一个常见的做法就是,在每一个 Epoch 开始之前,会分一次 Batch,然后呢,每一个 Epoch 的 Batch 都不一样,就是第一个 Epoch,我们分这样子的 Batch,第二个 Epoch,会重新再分 一次 Batch,所以哪些资料在同一个 Batch 里面,每一个 Epoch 都不一样的,这件事情叫做 Shuffle。
从上图可以看出,大的 Batch,这个 Update 比较稳定。小的 Batch,它的 Gradient 的方向比较 Noisy。
那么通常我们会觉得大的Batch计算速度比小的Batch慢,当然这并不是正确的见解,下面我们会给出解答(1.1.1和1.1.2)。那么还有一个问题,update 的稳定和noisy,到底哪个效果会更好呢?(1.1.3和1.1.4)
你会发现说 Batch Size 从1到1000,计算出 Gradient 所花费的时间几乎是一样的。因为在实际上做运算的时候,我们有 GPU,可以做并行运算。当然 GPU 平行运算的能力还是有它的极限,当你的 Batch Size 真的非常非常巨大的时候。GPU 在跑完一个 Batch,计算出 Gradient 所花费的时间。还是会随著 Batch Size 的增加,而逐渐增长。
左边这个图是拿一个 Batch 出来计算一个 Gradient,Update一次参数所需要的时间。右边这个图是跑完一个完整的 Epoch需要花的时间。
当你的 Batch Size 小的时候,你要跑完一个 Epoch,花的时间是比大的 Batch Size 还要多的。为什么呢?
假设我们的训练资料是60000,从前面所讲的,Batch Size为1和1000时,在计算Gradient所花费的时间是差不多的。但是Batch Size=1,需要更新60000次。而Batch Size=1000,只需要更新60次。相比起来,它们所花时间的差距量就非常可观了。
Noisy 的 Gradient,反而可以帮助 Training。而产生这个现象是 Optimization 的问题,代表当你用大的 Batch Size 的时候,你的Optimization 可能会有问题,小的 Batch Size,Optimization 的结果反而是比较好的。为什么呢?
假设你是 Full Batch,那你今天在 Update 你的参数的时候,你就是沿着一个 Loss Function来Update 参数,今天 Update 参数的时候走到一个 Local Minima或者一个 Saddle Point,显然就停下来了,Gradient 是零。如果你不特别去看Hession的话,那你用 Gradient Descent 的方法,你就没有办法再更新你的参数了。
但是假如是Small Batch的话,因为我们是挑一个Batch出来,算它的Loss,也就是每次在Update参数的时候,你用的Loss Function都是有差异的。如上图两个Batch对应两个Loss函数(L1和L2)。假设你用L1算Gradient的时候是零,但是没关系,我们可以换下一个Batch,用L2再算Gradient。
因此你还是有办法 Training 你的 Model,还是有办法让你的 Loss 变小,所以今天这种 Noisy的 Update 的 方式,结果反而对 Training是有帮助的。
其实小的 Batch 也对 Testing 有帮助。
有实验做过,是就算是在 Training 的时候结果差不多,Testing 的时候你还是看到了,大的 Batch 居然比小的 Batch差。有一个解释(这个其实还是一个尚待研究的问题)
假设在在这个 Training Loss 上面有很多个 Local Minima。但是这个 Local Minima还是有好坏之分的。如果一个 Local Minima 它在一个峡谷里面,它是坏的 Minima。如果它在一个平原上,它是好的Minima。为什么会有这样的差异呢?
那我们就假设说这个 Training 跟 Testing 的差距就是把 Training 的 Loss这个 Function 往右平移一点就是Testing的Loss Function。这时候你会发现,对左边这个在一个盆地里面的 Minima 来说,它的在 Training 跟 Testing 上面的结果不会差太多。但是对右边这个在峡谷里面的 Minima 来说,就可以说是天差地别了。
很多人相信这个大的 Batch Size,会让我们倾向于走到峡谷里面,而小的 Batch Size,倾向于走到盆地里面。
解释是小的 Batch,它有很多的 Loss,它每次 Update 的方向都不太一样,所以如 果今天这个峡谷非常地窄,它可能一个不小心就跳出去了,,之后如果有一个非常宽的盆地才会停下来。那对于大的 Batch Size,反正它就是顺着规定 Update,然后它就很有可能,走到一个比较小的峡谷里面。
- 从计算时间上看:大的Batch Size计算Gradient的速度和小的Batch Size相差不大,除非Batch Size是非常大那种。但是从一个 Epoch 需要的时间,小的 Batch 比较长,大的Batch 反而是比较快的。
- 从更新效果上看:Small Batch在Optimization 的时候会占到优势。
- 也就是说大的Batch计算时间短,训练效果差。(相对小的Batch,小Batch反之。)因此Batch Size也成为一个你需要去调整的超参数。
动量,可以想象在物理世界里,一个球如果从高处滚下来,就算滚到 Saddle Point,如果有惯性,它还是会继续往右走。甚至它走到一个 Local Minima,如果今天它的动量够大的话,它还是会继续往右走,甚至翻过这个小坡然后继续往右走。
接下来回顾一下一般的Gradient Descent,初始化一个参数叫做,然后计算一下 Gradient,计算完我们往 Gradient 的反方向去 Update 参数:
我们到了新的参数以后,再计算一次 Gradient,再往 Gradient 的反方向更新参数。这个 Process 就一直这样子下去。
实质上就是说我们在每一次移动的时候,考虑Gradient的反方向 + 上一步移动的方向,两者加起来的结果去调整我们的参数。(当然看到后面会有另一个解读)
第一步因为m0 = 0,所以化简后和Gradient Desend是没区别的。
我们直接讲第二步,g1告诉我们要往红色的反方向走,上一步移动的方向m1告诉我们要往蓝色虚线走。把两者相加起来,走两者的折中,也就是往蓝色m2这一个方向走。
每一步的移动,我们都用 m 来表示,那这个 m 其实可以写成之前所有算出来的Gradient 的Weighted Sum。从下边这个式子,其实就可以轻易的看出来:
那么现在就有了另外一个解读:所谓的 Momentum,当加上 Momentum 的时候,我们 Update 的方向,不是只考虑现在的 Gradient,而是考虑过去所有 Gradient 的总和!
所以通过这个解读我们就可以明白为什么Momentum可以逃离Saddle point 和 local minima了!
当我们走到一个 Local Minima时,一般 Gradient Descent 就无法向前走了,因为当前的 Gradient 已经为0,那走到 Saddle Point 也一样。如果有 Momentum 的话,你还是有办法继续走下去,因为Momentum考虑的是所有Gradient的总和,那么它的值有可能让你继续往前走。
参考:李宏毅机器学习