Small gradient
当我们在做优化的时候,有时候会发现,随着参数不断更新,loss并不会再下降,仍然是一个我们并不满意的值,并没有发挥出深度网络的优势,说明我们的优化存在一些问题。
或者一开始我们的模型就没有训练成功,loss值怎么都没有下降。
之前在gradient descent的部分我们就有学习到,它的限制主要有方面:
- local minima
- saddle point的微分值为0,但微分值的0的点也不一定接近local minima
就像图中这个例子里,它就像是一个马鞍的形状,所有被称为saddle point,中文就可以翻译为鞍点
我们把以上两种情况,gradient为零的点统称为critical point
如何分辨local minima 和 saddle point?
为什么我们想要知道是卡在local minima 还是 saddle point呢?
- 如果是卡在local minima,那可能就已经无路可走了,因为已经到了附近的最低点;
- 如果是saddle point,只要能逃离,还是有可能降低loss的。
Warning of Math
如果我们想知道到底是哪
点,那我们应该要知道loss function的形状,network本身很复杂,用复杂network算出来的loss function显然也很复杂。
Tayler Series Approximation
假设这个蓝色的
θ
′
\theta^{\prime}
θ′,在它附近的loss function,写出来就像这个样子
这个式子就是Tayler Series Appoximation泰勒级数展开,这一串理主要包含的东西有
- 第一项是 L ( θ ′ L(\theta^{\prime} L(θ′},就告诉我们说,当 θ \theta θ跟 θ ′ \theta^{\prime} θ′很近的时候,结果还蛮靠近的
- 第二项是
(
θ
−
θ
′
)
T
g
(\theta - \theta ^{\prime})^Tg
(θ−θ′)Tg
g是一个向量,这个g就是我们的gradient,我们用绿色的这个g来代表gradient,这个gradient会弥补 θ ′ \theta^{\prime} θ′和 θ \theta θ之间的差距 - 第三项与Hessian有关,这边有一个H
这个叫做Hessian,它是一个矩阵,这个第三项是,再 ( θ − θ ′ ) T H ( θ − θ ′ ) (\theta - \theta^{\prime})^TH(\theta - \theta^{\prime}) (θ−θ′)TH(θ−θ′),所以第三项会再补足,再加上gradient以后,与真正的L(θ)之间的差距.H裡面放的是L的二次微分,它第i个row,第j个column的值,就是把θ的第i个component,对L作微分,再把θ的第j个component,对L作微分,再把θ的第i个component,对L作微分,做两次微分以后的结果 就是这个 H i j H_{ij} Hij
当我们到一个critical point的时候,意味着gradient为0,也就是不用考虑绿色的一项
我们便可以根据红色的这一项来判断,在$\theta^{\prime}附近的error surface长什么样子,就可以判断它是local minima,local maxima,还是saddle point
如何判断呢?
为了符号方便,我们用
v
v
v来表示
(
θ
−
θ
′
)
( \theta - \theta^{\prime} )
(θ−θ′)
但如果我们要代所有的
v
v
v去看
v
T
H
v
v^THv
vTHv是大于零还是小于零,难度比较大,有一个更加简便的方法去确认这一个条件会不会发生。
这个就直接告诉你结论,如果今天对所有的v而言,
t
T
H
v
t^THv
tTHv都大于零,那这种矩阵叫做positive definite 正定矩阵,positive definite的矩阵,它所有的eigen value特征值都是正的
所以如果你今天算出一个hessian,你不需要把它跟所有的v都乘看看,你只要去直接看这个H的eigen value,如果你发现
- 所有eigen value都是正的,那就代表说这个条件成立,就, t T H v t^THv tTHv会大于零,也就代表说是一个local minima。所以你从hessian metric可以看出,它是不是local minima,你只要算出hessian metric算完以后,看它的eigen value发现都是正的,它就是local minima。
- 那反过来说也是一样,如果今天在这个状况,对所有的v而言, t T H v t^THv tTHv小於零,那H是negative definite,那就代表所有eigen value都是负的,就保证他是local maxima
- 那如果eigen value有正有负,那就代表是saddle point
结论:你只要算出hessian,它是一个矩阵,这个矩阵如果它所有的eigen value,都是正的,那就代表我们现在在local minima,如果它有正有负,就代表在saddle point。
举例:
举一个非常简单的例子,这个network只有两层,每层一个神经元,且不存在激活函数,这个function可以表示为
y
=
w
1
∗
w
2
∗
x
y = w_1 * w_2 * x
y=w1∗w2∗x。我们用最简单的训练集来训练,这个训练集只包含一个data 1,它的target也是1,因此我们希望function的输出跟1越接近越好。
但我们没有办法直接画出这个function的error surface,但由于只有两个参数,我们可以穷举所有
w
1
w_1
w1和
w
2
w_2
w2的数值,算出所有
w
1
、
w
2
w_1、w_2
w1、w2数值所代出来的loss,然后就画出error surface如下图所示
四个角落loss是高的,那这个图上你可以看出来说,有一些critical point,这个黑点的地方(0,0),原点的地方是critical point,然后事实上,右上三个黑点也是一排critical point,左下三个点也是一排critical point
如果你更进一步要分析,他们是saddle point,还是local minima的话,那圆心这个地方,原点这个地方 它是saddle point,往左上这个方向走 loss会变大,往右下这个方向走 loss会变大,往左下这个方向走 loss会变小,往右下这个方向走 loss会变小,它是一个saddle point。
而这两群critical point,它们都是local minima,所以这个山沟里面,有一排local minima,这一排山沟里面有一排local minima,然后在原点的地方,有一个saddle point,这个是我们把error surface,暴力所有的参数,得到的loss function以后,得到的loss的值以后,画出error surface,可以得到这样的结论。
现在假设如果不暴力所有可能的loss,如果要直接算说一个点,是local minima,还是saddle point的话,怎么计算呢?
我们可以把loss的function写出来,这个loss的function这个L是
L
=
(
y
^
−
w
1
w
2
x
)
2
L = (\hat y - w_1w_2x)^2
L=(y^−w1w2x)2,我们求它的gradient,
w
1
w_1
w1对L的微分,
w
2
w_2
w2对L的微分。
这个东西就是所谓的gradient,什么时候会等于0呢?
举例来说,如果
w
1
=
0
,
w
2
=
0
w_1=0, w_2=0
w1=0,w2=0就在圆心这个地方,如果
w
1
=
0
w_1=0
w1=0代0,
w
2
=
0
w_2=0
w2=0代0,
w
1
=
0
w_1=0
w1=0对L的微分,
w
2
=
0
w_2=0
w2=0对L的微分,就都是0,这时候我们就知道,原点就是一个critical point,但它具体是什么我们还不知道,必须要看hessian才能够知道了。
当然 我们刚才已经暴力所有可能的w₁ w₂了,所以你已经知道说,它显然是一个saddle point,但是现在假设还没有暴力所有可能的loss,所以我们要看看能不能够用H,用Hessian看出它是什么样的critical point,那怎么算出这个H呢
H它是一个矩阵,这个矩阵里面元素就是L的二次微分,所以这个矩阵里面第一个row,第一个coloumn的位置,就是w₁对L微分两次,第一个row 第二个coloumn的位置,就是先用w₂对L作微分,再用w₁对L作微分,然后这边就是w₁对L作微分,w₂对L作微分,然后w₂对L微分两次,这四个值组合起来,就是我们的hessian,那这个hessian的值是多少呢。
这个hessian的式子是这样的一个矩阵
这个hessian告诉我们,它是local minima,还是saddle point呢,那你就要看这个矩阵的eigen value,算一下发现,这个矩阵有两个eigen value,2跟-2 eigen value有正有负,代表saddle point 。
如果卡在saddle point
如果卡在saddle point,H还可以指出之后更新参数的方向
我们这边假设
μ
\mu
μ是H的eigenvector特征向量,然后
λ
\lambda
λ是u的eigen value特征值。
如果我们把这边的
v
v
v换成
μ
\mu
μ的话,我们把乘在H的左边,跟H的右边,也就是
μ
T
H
μ
\mu^TH\mu
μTHμ,
H
μ
H\mu
Hμ会得到
λ
μ
\lambda\mu
λμ,因为
μ
\mu
μ是一个eigen vector。H乘上eigen vector特征向量会得到特征向量λ eigen value乘上eigen vector即
λ
μ
\lambda\mu
λμ
所以我们在这边得到
u
T
u^T
uT乘上KaTeX parse error: Undefined control sequence: \muu at position 1: \̲m̲u̲u̲,然后再整理一下,把
u
T
u^T
uT跟
u
u
u相乘,得到
∣
∣
u
∣
∣
2
||u||^2
∣∣u∣∣2,所有得到
λ
∣
∣
u
∣
∣
2
\lambda||u||^2
λ∣∣u∣∣2
所以这意思是说假设
θ
−
θ
′
=
μ
\theta - \theta^{\prime} = \mu
θ−θ′=μ,那这一项
(
θ
−
θ
′
)
T
H
(
θ
−
θ
′
)
(\theta - \theta^{\prime})^TH(\theta - \theta^{\prime})
(θ−θ′)TH(θ−θ′)就是负的,也就是说
L
(
θ
)
<
L
(
θ
′
)
L(\theta) < L(\theta^{\prime})
L(θ)<L(θ′),假设
L
(
θ
)
<
L
(
θ
′
)
=
μ
L(\theta) < L(\theta^{\prime}) = \mu
L(θ)<L(θ′)=μ,也就是,你在θ’的位置加上u,沿著u的方向做update得到θ,你就可以让loss变小
所以虽然在critical point没有gradient,如果我们今天是在一个saddle point,你也不一定要惊慌,你只要找出负的eigen value,再找出它对应的eigen vector,用这个eigen vector去加θ’,就可以找到一个新的点,这个点的loss比原来还要低。
Batch and Momentum
上次又说到,我们实际上在算微分的时候,并不是真的对所有data算出来的L作微分,是把所有的data分成一个一个的batch,也可以称为mini batch
每次我们在更新参数的时候,我们就是计算一个batch的loss,算gradient,然后更新参数,所有的batch更新一遍之后,就称为一个epoch,事实上,在做这些batch的时候,你会做一件事情叫做shuffle,Shuffle 有很多不同的做法,但一个常见的做法就是,在每一个 Epoch 开始之前,会分一次 Batch,然后呢,每一个 Epoch 的 Batch 都不一样,就是第一个 Epoch,我们分这样子的 Batch,第二个 Epoch,会重新再分一次 Batch,所以哪些资料在同一个 Batch 裡面,每一个 Epoch 都不一样的这件事情,叫做 Shuffle。
small batch v.s. large batch
我们先解释为什么要用batch,再说batch对training带来了什么样的帮助。
在左边的case中,模型必须要20笔训练资料都看完,才能够计算loss,才能够计算gradient,所以我们必须要把所有20笔examples都看完之后,我们的参数才能够更新一次,就假设开始的地方在上边,把所有资料看完之后,更新参数就从这里移动到下边。
如果 Batch Size 等于1的话,代表我们只需要拿一笔资料出来算 Loss,我们就可以 Update 我们的参数,所以每次我们 Update 参数的时候,看一笔资料就好,所以我们开始的点在这边,看一笔资料 就 Update 一次参数,再看一笔资料 就 Update 一次参数,如果今天总共有20笔资料的话 那在每一个 Epoch 里面,我们的参数会 Update 20次,那不过,因为我们现在是只看一笔资料,就 Update 一次参数,所以用一笔资料算出来的 Loss,显然是比较 Noisy 的,所以我们今天 Update 的方向,你会发现它是曲曲折折的
左边的方式,需要的时间比较长,因为它要全看过一遍才能更新参数,但它这每一步走的都是稳的,右边的方式,batch size等于1,更新的比较快,变化比较大。
但是在考虑并行运算的情况下,左边所需要的时间不一定比较长
Larger batch size does not require longer time to compute gradient
这边是真正的实验结果了,事实上,比较大的 Batch Size,你要算 Loss,再进而算 Gradient,所需要的时间,不一定比小的 Batch Size 要花的时间长
那以下是做在一个叫做 MNIST 上面,MNIST (Mixed National Institute of Standards and Technology database)是美国国家标准与技术研究院收集整理的大型手写数字数据库,机器要做的事情,就是给它一张图片,然后判断这张图片,是0到9的哪一个数字,它要做数字的分类,那 MNIST 呢 是机器学习的helloworld,就是假设你今天,从来没有做过机器学习的任务,一般大家第一个会尝试的机器学习的任务,往往就是做 MNIST 做手写数字辨识,
这边我们就是做了一个实验,我们想要知道说,给机器一个 Batch,它要计算出 Gradient,进而 Update 参数,到底需要花多少的时间
这边列出了 Batch Size 等于1 等于10,等于100 等于1000 所需要耗费的时间
你会发现说 Batch Size 从1到1000,需要耗费的时间几乎是一样的,你可能直觉上认为有1000笔资料,那需要计算 Loss,然后计算 Gradient,花的时间不会是一笔资料的1000倍吗,但是实际上并不是这样的
因为在实际上做运算的时候,我们有 GPU,可以做并行运算,是因为你可以做平行运算的关系,这1000笔资料是平行处理的,所以1000笔资料所花的时间,并不是一笔资料的1000倍,当然 GPU 平行运算的能力还是有它的极限,当你的 Batch Size 真的非常非常巨大的时候,GPU 在跑完一个 Batch,计算出 Gradient 所花费的时间,还是会随着 Batch Size 的增加,而逐渐增长
所以今天如果 Batch Size 是从1到1000,所需要的时间几乎是一样的,但是当你的 Batch Size 增加到 10000,乃至增加到60000的时候,你就会发现 GPU 要算完一个 Batch,把这个 Batch 里面的资料都拿出来算 Loss,再进而算 Gradient,所要耗费的时间,确实有随着 Batch Size 的增加而逐渐增长,但你会发现这边用的是 V100,所以它挺厉害的,给它60000笔资料,一个 Batch 里面,塞了60000笔资料,它在10秒钟之内,也是把 Gradient 就算出来。
Smaller batch requires longer time for one epoch
所以 GPU 虽然有平行运算的能力,但它平行运算能力终究是有个极限,所以 Batch Size 真的很大的时候,时间还是会增加的
但是因为有平行运算的能力,因此实际上,当你的 Batch Size 小的时候,你要跑完一个 Epoch,花的时间是比大的 Batch Size 还要多的
如果今天假设我们的训练资料只有60000笔,那 Batch Size 设1,那你要60000个 Update 才能跑完一个 Epoch,如果今天是 Batch Size为1000,你要60个 Update 才能跑完一个 Epoch,假设今天一个 Batch Size 等于1000,要算 Gradient 的时间根本差不多,那60000次 Update,跟60次 Update 比起来,它的时间的差距量就非常可观了。
在没有考虑平行运算的时候,你觉得大的 Batch 比较慢,但实际上,在有考虑平行运算的时候,一个 Epoch 大的 Batch 花的时间反而是比较少的。
这其实是因为optimization的问题,代表你用大的batch size的时候,你的optimization可能会有问题
“Noisy” update is better for training
“Noisy” update is better for generalization
小的 Batch 也对 Testing 有帮助。
假设你有一些方法,你努力的调大的 Batch 的 Learning Rate,然后想办法把大的 Batch,跟小的 Batch Training 得一样好,结果你会发现小的 Batch,居然在 Testing 的时候会是比较好的,那以下这个实验结果是引用自,On Large-Batch Training For Deep Learning,Generalization Gap And Sharp Minima,这篇 Paper 的实验结果。
那这篇 Paper 里面,作者 Train 了六个 Network 里面有 CNN 的,有 Fully Connected Network 的,做在不同的 Cover 上,来代表这个实验是很泛用的,在很多不同的 Case 都观察到一样的结果,那它有小的 Batch,一个 Batch 里面有256笔 Example,大的 Batch 就是那个 Data Set 乘 0.1,Data Set 乘 0.1,Data Set 有60000笔,那你就是一个 Batch 里面有6000笔资料
然后他想办法,在大的 Batch 跟小的 Batch,都 Train 到差不多的 Training 的 Accuracy,所以刚才我们看到的结果是,Batch Size 大的时候,Training Accuracy 就已经差掉了,这边不是想办法 Train 到大的 Batch 的时候,Training Accuracy 跟小的 Batch,其实是差不多的
但是就算是在 Training 的时候结果差不多,Testing 的时候你还是看到了,小的 Batch 居然比大的 Batch 差,Training 的时候都很好,Testing 的时候小的 Batch 差,代表 Over Fitting,这个才是 Over Fitting ,那为什么会有这样子的现象呢?在这篇文章里面也给出了一个解释
累了,明天再继续,内容太多了。