李宏毅 机器学习(3)- dl调优技巧
本篇笔记摘抄了很多别人做的笔记部分,节约时间啦嘿嘿
像是knn、decision tree的model,如果performance很差,那也不必要检查training set 的表现,因为都会接近100%这样。
但是deep learning就不一样,其实不太容易overfitting,我们要做的其实是先检查3个步骤,来使得training set 上面的表现变好
这种情况就不是overfitting, training set就没有train好
不同方法往往有使用的局限性,不要乱用
一、 training data 表现不好怎么办?
1、New activation function
如果你今天的training结果不好,很有可能是因为你的network架构设计得不好。举例来说,可能你用的activation function是对training比较不利的,那你就尝试着换一些新的activation function,也许可以带来比较好的结果
在1980年代,比较常用的activation function是sigmoid function,如果现在我们使用sigmoid function,你会发现deeper不一定imply better,下图是在MNIST手写数字识别上的结果,当layer越来越多的时候,accuracy一开始持平,后来就掉下去了,在layer是9层、10层的时候,整个结果就崩溃了;但注意!9层、10层的情况并不能被认为是因为参数太多而导致overfitting,实际上这张图就只是training set的结果,你都不知道testing的情况,又哪来的overfitting之说呢?
发生这样的事情原因就是:Vanishing Gradient Problem
sigmoid function的锅,最开始变化的w很大,但是呢经过很多层的sigmoid function,其对于cost的影响就变得很小了,对output的影响很小,导致前面没train好,后面已经收敛了
一开始人们的解决方法 是train RBM,一层一层pre-train,其实简单的解决方法是:换 activation function
ReLu function
解释
下图是ReLU的neural network,以ReLU作为activation function的neuron,它的output要么等于0,要么等于input
当output=input的时候,这个activation function就是linear的;而output=0的neuron对整个network是没有任何作用的,因此可以把它们从network中拿掉
拿掉所有output为0的neuron后如下图所示,此时整个network就变成了一个瘦长的linear network,linear的好处是,output=input,不会像sigmoid function一样使input产生的影响逐层递减
Q1:这里就会有一个问题,我们之所以使用deep learning,就是因为想要一个non-linear、比较复杂的function,而使用ReLU不就会让它变成一个linear function吗?这样得到的function不是会变得很弱吗?
A:其实,使用ReLU之后的network整体来说还是non-linear的,如果你对input做小小的改变,不改变neuron的operation region的话,那network就是一个linear function;但是,如果你对input做比较大的改变,导致neuron的operation region被改变的话,比如从output=0转变到了output=input,network整体上就变成了non-linear function
注:这里的region是指input z<0和input z>0的两个范围
Q2:还有另外一个问题,我们对loss function做gradient descent,要求neural network是可以做微分的,但ReLU是一个分段函数,它是不能微分的(至少在z=0这个点是不可微的),那该怎么办呢?
A:在实际操作上,当region的范围处于z>0时,微分值gradient就是1;当region的范围处于z<0时,微分值gradient就是0;当z为0时,就不要管它,相当于把它从network里面拿掉
进一步的知识关于ReLU
当input<0的时候,output=0,此时微分值gradient也为0,你就没有办法去update参数了,所以我们应该让input<0的时候,微分后还能有一点点的值,比如令a=0.01z,这个东西就叫做Leaky ReLU
既然a可以等于0.01z,那这个z的系数可不可以是0.07、0.08之类呢?所以就有人提出了Parametric ReLU,其中阿尔法并不是固定的值,而是network的一个参数,它可以通过training data学出来,甚至每个neuron都可以有不同的值
Maxout的想法是,让network自动去学习它的activation function,那Maxout network就可以自动学出ReLU,也可以学出其他的activation function,这一切都是由training data来决定的
特别好理解的算法: Max的 Out
在Maxout network里,我们不通过activation function,而是事先决定好将某几个“neuron”的input分为一个group,比如5,7分为一个group,然后在这个group里选取一个最大值7作为output。
这个过程就好像在一个layer上做Max Pooling一样,它和原来的network不同之处在于,它把原来几个“neuron”的input按一定规则组成了一个group,然后并没有使它们通过activation function,而是选取其中的最大值当做这几个“neuron”的output
当然,实际上原来的”neuron“早就已经不存在了,这几个被合并的“neuron”应当被看做是一个新的neuron,这个新的neuron的input是原来几个“neuron”的input组成的vector,output则取input的最大值,而并非由activation function产生
在实际操作上,几个element被分为一个group这件事情是由你自己决定的,它就是network structure里一个需要被调的参数,不一定要跟上图一样两个分为一组
maxout怎么得到ReLU的呢? 看左图,线性的直线经过ReLU变成绿色直线。 右图,如果 z2的参数都为0,那么1输出的会是x轴这条红色直线,而z1输出是蓝色这条直线,maxout以后得到ReLU一样的绿色直线。
也可以得到除了ReLU的其他activation function,是由network的参数w,b决定的,因此它是一个Learnable Activation Function,具体的形状可以根据training data去generate出来
Maxout可以实现任何piecewise linear convex activation function(分段线性凸激活函数),其中这个activation function被分为多少段,取决于你把多少个element z放到一个group里,下图分别是2个element一组和3个element一组的activation function的不同形状
那么怎么train这个东西呢? 其实Max operation就是linear的operation,只是它仅接在前面这个group里的某一个element上,因此我们可以把那些并没有被Max连接到的element通通拿掉,从而得到一个比较细长的linear network 实际上我们真正训练的并不是一个含有max函数的network,而是一个化简后如下图所示的linear network;当我们还没有真正开始训练模型的时候,此时这个network含有max函数无法微分,但是只要真的丢进去了一笔data,network就会马上根据这笔data确定具体的形状,此时max函数的问题已经被实际数据给解决了,所以我们完全可以根据这笔training data使用Backpropagation的方法去训练被network留下来的参数
所以我们担心的max函数无法微分,它只是理论上的问题;在具体的实践上,我们完全可以先根据data把max函数转化为某个具体的函数,再对这个转化后的thiner linear network进行微分
诶,那就有一个问题,被扔掉的参数怎么办?不train了吗?
这也只是个理论上的问题,在实际操作上,我们之前已经提到过,每个linear network的structure都是由input的那一笔data来决定的,当你input不同data的时候,得到的network structure是不同的,留在network里面的参数也是不同的,由于我们有很多很多笔training data,所以network的structure在训练中不断地变换,实际上最后每一个weight参数都会被train到
2、Adaptive Learning Rate
复习adagrad
Adagrad的精神是,假设我们考虑两个参数w1,w2,如果在w2这个方向上,平常的gradient都比较小,那它是比较平坦的,于是就给它比较大的learning rate;反过来说,在w2这个方向上,平常gradient都比较大,那它是比较陡峭的,于是给它比较小的learning rate
adagrad的局限性 和RMSProp
不同情况下,我们的loss function可能会很复杂,在某一条线上的陡峭率可能是先平缓再特别陡峭,我们需要更dynamic的方法,如果还用adagrad,他累计之前的微分值,就不够dynamic了
RMSProp跟Adagrad不同之处在于,Adagrad的分母是对过程中所有的gradient取平方和开根号,也就是说Adagrad考虑的是整个过程平均的gradient信息;而RMSProp虽然也是对所有的gradient进行平方和开根号,但是它用一个α来调整对不同gradient的使用程度,比如你把α的值设的小一点,意思就是你更倾向于相信新的gradient所告诉你的error surface的平滑或陡峭程度,而比较无视于旧的gradient所提供给你的information
Momentum方法解决local minimum
其实不同太担心local minimum,因为一旦出现local minima,它就必须在每一个dimension都是下图中这种山谷的低谷形状,假设山谷的低谷出现的概率为p,由于我们的network有非常非常多的参数,这里假设有1000个参数,每一个参数都要位于山谷的低谷之处,这件事发生的概率为p的一千次,当你的network越复杂,参数越多,这件事发生的概率就越低
但处理local minimum有个方法就是惯性, 举一个生活例子:
假设在有一个球从左上角滚下来,它会滚到plateau的地方、local minima的地方,但是由于惯性它还会继续往前走一段路程,假设前面的坡没有很陡,这个球就很有可能翻过山坡,走到比local minima还要好的地方。
把惯性塞到gradient descent里面,这件事情就叫做Momentum
当我们在gradient descent里加上Momentum的时候,每一次update的方向,不再只考虑gradient的方向,还要考虑上一次update的方向,那这里我们就用一个变量v去记录前一个时间点update的方向
简单的说就是每次计算movement的时候考虑上次的。
另一种方法来理解Momentum这件事,其实你在每一个时间点移动的步伐v,包括大小和方向,就是过去所有gradient的加权和
由于lambda的值小于1,因此该加权意味着越是之前的gradient,它的权重就越小,也就是说,你更在意的是现在的gradient,但是过去的所有gradient也要对你现在update的方向有一定程度的影响力,这就是Momentum
下图中,红色实线是gradient建议我们走的方向,直观上看就是根据坡度要走的方向;绿色虚线是Momentum建议我们走的方向,实际上就是上一次移动的方向;蓝色实线则是最终真正走的方向
如果我们今天走到local minimum的地方,此时gradient是0,红色箭头没有指向,它就会告诉你就停在这里吧,但是Momentum也就是绿色箭头,它指向右侧就是告诉你之前是要走向右边的,所以你仍然应该要继续往右走,所以最后你参数update的方向仍然会继续向右;你甚至可以期待Momentum比较强,惯性的力量可以支撑着你走出这个谷底,去到loss更低的地方
Adam
其实RMSProp加上Momentum + bias correction,就可以得到Adam
二、testing data 表现不好怎么办?
1.Early Stopping
用validation set
2. Regularization
regularization就是在原来的loss function上额外增加几个term,比如我们要minimize的loss function原先应该是square error或cross entropy,那在做Regularization的时候,就在后面加一个Regularization的term
L2 regularization
regularization term可以是参数的L2 norm(L2正规化),所谓的L2 norm,就是把model参数集里的每一个参数都取平方然后求和,这件事被称作L2 regularization,即
通常我们在做regularization的时候,新加的term里是不会考虑bias这一项的,因为加regularization的目的是为了让我们的function更平滑,而bias通常是跟function的平滑程度没有关系的
使用L2 regularization可以让weight每次都变得更小一点,这就叫做Weight Decay(权重衰减)
在deep learning里面,regularization虽然有帮助,但它的重要性往往没有SVM这类方法来得高,因为我们在做neural network的时候,通常都是从一个很小的、接近于0的值开始初始参数的,而做update的时候,通常都是让参数离0越来越远,但是regularization要达到的目的,就是希望我们的参数不要离0太远
如果你做的是Early Stopping,它会减少update的次数,其实也会避免你的参数离0太远,这跟regularization做的事情是很接近的
所以在neural network里面,regularization的作用并没有SVM来的重要,SVM其实是explicitly把regularization这件事情写在了它的objective function(目标函数)里面,SVM是要去解一个convex optimization problem,因此它解的时候不一定会有iteration的过程,它不会有Early Stopping这件事,而是一步就可以走到那个最好的结果了,所以你没有办法用Early Stopping防止它离目标太远,你必须要把regularization explicitly加到你的loss function里面去
L1 regularization
这个式子告诉我们,每次update的时候,不管三七二十一都要减去一个值,如果w是正的,sgn是+1,就会变成减一个positive的值让你的参数变小;如果w是负的,sgn是-1,就会变成加一个值让你的参数变大;总之就是让它们的绝对值减小至接近于0
L1 VS L2
因此,当参数w的绝对值比较大的时候,L2会让w下降得更快,而L1每次update只让w减去一个固定的值,train完以后可能还会有很多比较大的参数;当参数w的绝对值比较小的时候,L2的下降速度就会变得很慢,train出来的参数平均都是比较小的,而L1每次下降一个固定的value,train出来的参数是比较sparse的,这些参数有很多是接近0的值,也会有很大的值
nn和训练人脑异曲同工,train阿train 会让一些参数变成0, 也就是减少不必要的neural,会提高performance
3. Dropout
training
在training的时候,每次update参数之前,我们对每一个neuron(也包括input layer的“neuron”)做sampling(抽样) ,每个neuron都有p%的几率会被丢掉,如果某个neuron被丢掉的话,跟它相连的weight也都要被丢掉
实际上就是每次update参数之前都通过抽样只保留network中的一部分neuron来做训练
做完sampling以后,network structure就会变得比较细长了,然后你再去train这个细长的network
注:每次update参数之前都要做一遍sampling,所以每次update参数的时候,拿来training的network structure都是不一样的;你可能会觉得这个方法跟前面提到的Maxout会有一点像,但实际上,Maxout是每一笔data对应的network structure不同,而Dropout是每一次update的network structure都是不同的(每一个minibatch对应着一次update,而一个minibatch里含有很多笔data)
testing
在使用dropout方法做testing的时候要注意两件事情:
- testing的时候不做dropout,所有的neuron都要被用到
- 假设在training的时候,dropout rate是p%,从training data中被learn出来的所有weight都要乘上(1-p%)才能被当做testing的weight使用
intuitive reasoning
在training的时候,会丢掉一些neuron,就好像是你要练轻功的时候,会在脚上绑一些重物;然后,你在实际战斗的时候,就是实际testing的时候,是没有dropout的,就相当于把重物拿下来,所以你就会变得很强
另一个直觉的理由是这样,neural network里面的每一个neuron就是一个学生,那大家被连接在一起就是大家听到说要组队做final project,那在一个团队里总是有人会拖后腿,就是他会dropout,所以假设你觉得自己的队友会dropout,这个时候你就会想要好好做,然后去carry这个队友,这就是training的过程
那实际在testing的时候,其实大家都有好好做,没有人需要被carry,由于每个人都比一般情况下更努力,所以得到的结果会是更好的,这也就是testing的时候不做dropout的原因
假设现在的dropout rate是50%,那在training的时候,你总是期望每次update之前会丢掉一半的neuron,就像下图左侧所示,在这种情况下你learn好了一组weight参数,然后拿去testing
但是在testing的时候是没有dropout的,所以如果testing使用的是和training同一组weight,那左侧得到的output z和右侧得到的output z‘,它们的值其实是会相差两倍的,这样会造成testing的结果与training的结果并不match,最终的performance反而会变差
那这个时候,你就需要把右侧testing中所有的weight乘上0.5,然后做normalization,这样z就会等于z’,使得testing的结果与training的结果是比较match的
more reasoning
其实也是一种ensemble的方法,类似于random forest。
在training network的时候,每次拿一个minibatch出来就做一次update,而根据dropout的特性,每次update之前都要对所有的neuron进行sample,因此每一个minibatch所训练的network都是不同的
假设我们有M个neuron,每个neuron都有可能drop或不drop,所以总共可能的network数量有2的m次方个;所以当你在做dropout的时候,相当于是在用很多个minibatch分别去训练很多个network(一个minibatch一般设置为100笔data),由于update次数是有限的,所以做了几次update,就相当于train了几个不同的network,最多可以训练到2的m次方个network
每个network都只用一个minibatch的data来train,可能会让人感到不安,一个batch才100笔data,怎么train一个network呢?其实没有关系,因为这些不同的network之间的参数是shared,也就是说,虽然一个network只能用一个minibatch来train,但同一个weight可以在不同的network里被不同的minibatch train,所以同一个weight实际上是被所有没有丢掉它的network一起share的,它是拿所有这些network的minibatch合起来一起train的结果
那按照ensemble这个方法的逻辑,在testing的时候,你把那train好的一大把network通通拿出来,然后把手上这一笔testing data丢到这把network里面去,每个network都给你吐出一个结果来,然后你把所有的结果平均起来 ,就是最后的output
但是在实际操作上,如下图左侧所示,这一把network实在太多了,你没有办法每一个network都丢一个input进去,再把它们的output平均起来,这样运算量太大了
所以dropout最神奇的地方是,当你并没有把这些network分开考虑,而是用一个完整的network,这个network的weight是用之前那一把network train出来的对应weight乘上(1-p%),然后再把手上这笔testing data丢进这个完整的network,得到的output跟network分开考虑的ensemble的output,是惊人的相近
也就是说下图左侧ensemble的做法和右侧dropout的做法,得到的结果是approximate(近似)的
举一个简单的线性例子: 想要呈现的是,在这个最简单的case里面,用不同的network structure做ensemble这件事情,跟我们用一整个network,并且把weight乘上一个值而不做ensemble所得到的output,其实是一样的
如果network很接近linear的话,dropout所得到的performance会比较好,而ReLU和Maxout的network相对来说是比较接近于linear的,所以我们通常会把含有ReLU或Maxout的network与Dropout配合起来使用
summary
重新拿出这张图:
- training 不够好:换activation function、换调节learning rate方法
- testing 不够好: validation set、regularization、dropout(线性network效果好)