Machine Learning —— Tips of DNN

Machine Learning —— Tips of DNN

本文会顺带解决CNN部分的两个问题
  • max pooling架构中用到的max无法微分,那在gradient descent的时候该如何处理
  • L1 的Regression到底是什么
针对training set和testing set上的performance分别提出针对性的解决方法
  • 在training set上准确率不高:
    – new activation function:ReLU、Maxout
    – adaptive learning rate:Adagrad、RMSProp、Momentum、Adam
  • 在testing set上准确率不高:Early Stopping、Regularization or Dropout

Recipe of Deep Learning

Three step of deep learning

  • Define the function set(network structure)
  • Goodness of function(loss function – cross entropy)
  • Pick the best function(gradient descent – optimization)

做完这三步以后,会得到一个更好的neural network,那接下来你要做什么事情呢?
在这里插入图片描述

Good Results on Training Data?

第一件事是,提高model在training set上的正确率

在training的时候,deep learning并不是像k nearest neighbor这种方法一样,一训练就可以得到非常好的正确率,它有可能在training set上根本没有办法给你一个好的正确率,所以,这个时候你要回头去检查在前面的step里面要做什么样的修改,好让你在training set上可以得到比较高的正确率

Good Results on Testing Data?

接下来要做的事是,提高model在testing set上的正确率

设现在已经在training set上得到好的performance了,那接下来就把model apply到testing set上,假如得到的结果不好,这个情况下发生的才是Overfitting,也就是在training set上得到好的结果,却在testing set上得到不好的结果

试着解决overfitting,有时候加了新的technique,想要overcome overfitting这个problem的时候,其实反而会让training set上的结果变坏;在做完这一步的修改以后,要先回头去检查新的model在training set上的结果,如果这个结果变坏的话,就要从头对network training的process做一些调整,那如果同时在training set还有testing set上都得到好结果的话,你就成功了,最后就可以把系统真正用在application上面了

conclusion

当你在deep learning的文献上看到某种方法的时候,永远要想一下,这个方法是要解决什么样的问题,因为在deep learning里面,有两个问题:

  • 在training set上的performance不够好
  • 在testing set上的performance不够好
    在这里插入图片描述
    下面我们分别从Training data和Testing data两个问题出发,来讲述一些针对性优化的方法

Improve performance on Training Data

这一部分主要讲述如何在Training data上得到更好的performance,分为两个模块

  • New activation function
  • Adaptive Learning Rate

New activation function

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
在这里插入图片描述

Vanishing Gradient Problem

上面这个问题的原因不是overfitting,而是Vanishing Gradient(梯度消失)

当你把network叠得很深的时候,在靠近input的地方,这些参数的gradient(即对最后loss function的微分)是比较小的;而在比较靠近output的地方,它对loss的微分值会是比较大的

因此当你设定同样learning rate的时候

  • 靠近input的地方,它参数的update是很慢的;
  • 靠近output的地方,它参数的update是比较快的;

所以在靠近input的地方,参数几乎还是random的时候,output就已经根据这些random的结果找到了一个local minima,然后就converge(收敛)了,参数的loss下降的速度变得很慢,你就会觉得gradient已经接近于0了,于是把程序停掉了,由于这个converge,是几乎base on random的参数,所以model的参数并没有被训练充分,那在training data上得到的结果肯定是很差的
在这里插入图片描述
从直觉上来想:

某一个参数 w w w对total cost的偏微分,即gradient ∂ l ∂ w \frac{\partial l}{\partial w} wl,我们把第一个layer里的某一个参数 w w w加上 △ w \vartriangle w w,看对network的output和target之间的loss有什么影响

△ w \vartriangle w w通过sigmoid function之后,得到的output会变小,因此改变某一个参数的weight。会对某个neuron的output产生影响,但是这个影响会随着层数的增加而衰减

因此即使 △ w \vartriangle w w很大,但每经过一个sigmoid function都会被缩小一次,所以network越深, △ w \vartriangle w w的影响越小,相应的也导致input对loss的影响会比较小,于是靠近input的weight对loss的gradient远小于output的gradient
在这里插入图片描述
其实改一下activation function可能就可以handle这个问题

ReLU(Rectified Linear Unit)
introduction

现在比较常用的activation function叫做Rectified Linear Unit(整流线性单元函数,又称修正线性单元),它的缩写是ReLU,该函数形状如下图所示,z为input,a为output,如果input>0则output = input,如果input<0则output = 0
在这里插入图片描述
选择ReLU的理由如下:

  • 跟sigmoid function比起来,ReLU的运算快很多
  • 无穷多bias不同的sigmoid function叠加的结果会变成ReLU
  • ReLU可以处理Vanishing gradient的问题( the most important thing )
  • ReLU的想法结合了生物上的观察
handle Vanishing gradient problem

下图是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产生的影响逐层递减
在这里插入图片描述

  • Q:这里就会有一个问题,我们之所以使用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的两个范围)
  • Q:还有另外一个问题,我们对loss function做gradient descent,要求neural network是可以做微分的,但ReLU是一个分段函数,它是不能微分的(至少在z=0这个点是不可微的),那该怎么办呢?
    – A:在实际操作上,当region的范围处于z>0时,微分值gradient就是1;当region的范围处于z<0时,微分值gradient就是0;当z为0时,就不要管它,相当于把它从network里面拿掉
ReLU-variant —— Leaky ReLU

其实ReLU还存在一定的问题,比如当input<0的时候,output=0,此时微分值gradient也为0,你就没有办法去update参数了,所以我们应该让input<0的时候,微分后还能有一点点的值,比如令 a = 0.01 z a=0.01z a=0.01z,这个就叫做Leaky ReLU
在这里插入图片描述

Maxout
introduction

Maxout的想法是,让network自动去学习它的activation function,那Maxout network就可以自动学出ReLU,也可以学出其他的activation function,这一切都是由training data来决定的

假设现在有input x 1 , x 2 x_1,x_2 x1,x2,它们乘上几组不同的weight分别得到5,7,-1,1,这些值本来是不同neuron的input,它们要通过activation function变为neuron的output;但在Maxout network里,我们事先决定好将某几个“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

Maxout是如何模仿出ReLU这个activation function的呢?

图左上角是一个ReLU的neuron,它的input x会乘上neuron的weight w,再加上bias b,然后通过activation function-ReLU,得到output a

  • neuron的input为 z = w x + b z=wx+b z=wx+b,为下图左下角蓝线
  • neuron的output为 a = z ( z > 0 ) ; a = 0 ( z < 0 ) a=z(z>0);a=0(z<0) a=z(z>0);a=0(z<0),为左下角绿线

如果我们使用的是上图右上角所示的Maxout network,假设 z 1 z_1 z1的参数w和b与ReLU的参数一致,而 z 2 z_2 z2的参数w和b全部设为0,然后做Max Pooling,选取 z 1 , z 2 z_1,z_2 z1,z2较大值作为a 则:

  • z 1 = w x + b z_1=wx+b z1=wx+b为上图右下角蓝线
  • z 2 = 0 z_2=0 z2=0,为上图右下角红线
  • neuron的output为 m a x [ z 1 , z 2 ] max[z_1,z_2] max[z1,z2],为下图右下角绿线
    在这里插入图片描述
    这个时候得到的activation function的形状(绿线形状),是由network的参数 w , b , w ′ , b ′ w,b,w',b' w,b,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的不同形状

How to train Maxout

怎么去train一个Maxout network,如何解决Max不能微分的问题

假设在下面的Maxout network中,红框圈起来的部分为每个neuron的output
在这里插入图片描述
其实Max operation就是linear的operation,只是它仅接在前面这个group里的某一个element上,因此我们可以把那些并没有被Max连接到的element通通拿掉,从而得到一个比较细长的linear network

在具体的实践上,我们完全可以先根据data把max函数转化为某个具体的函数,再对这个转化后的thiner linear network进行微分
在这里插入图片描述
如果按照上面的做法,那岂不是只会train留在network里面的那些参数,剩下的参数该怎么办?那些被拿掉的直线(weight)岂不是永远也train不到了吗?

在实际操作上,我们之前已经提到过,每个linear network的structure都是由input的那一笔data来决定的,当你input不同data的时候,得到的network structure是不同的,留在network里面的参数也是不同的,由于我们有很多很多笔training data,所以network的structure在训练中不断地变换,实际上最后每一个weight参数都会被train到

Max Pooling有关max函数的微分问题采用跟Maxout一样的方案即可解决

Adaptive learning rate

Review - Adagrad

我们之前已经了解过Adagrad的做法,让每一个parameter都要有不同的learning rate

Adagrad的精神是,假设我们考虑两个参数 w 1 , w 2 w_1,w_2 w1,w2,如果在 w 1 w_1 w1这个方向上,平常的gradient都比较小,那么它是比较平坦的,于是就给它较大的learning rate;如果 w 2 w_2 w2这个方向上,平常的gradient都比较大,那么它是比较陡峭的,于是给它较小的learning rate
在这里插入图片描述
但我们实际面对的问题,很有可能远比Adagrad所能解决的问题要来的复杂,我们之前做Linear Regression的时候,我们做optimization的对象,也就是loss function,它是convex的形状;但实际上我们在做deep learning的时候,这个loss function可以是任何形状

RMSProp
learning rate

在下图所示的情况中,即使是在同一个方向上(如w1方向),loss function也有可能一会儿平坦一会儿陡峭,所以你要随时根据gradient的大小来快速地调整learning rate
在这里插入图片描述
所以真正要处理deep learning的问题,用Adagrad可能是不够的,你需要更dynamic的调整learning rate的方法,所以产生了Adagrad的进阶版——RMSProp

how to do RMSProp

RMSProp的做法如下:

我们的learning rate依旧设置为一个固定的值 η \eta η除掉一个变化的值 σ \sigma σ,而这个 σ \sigma σ等于上一个 σ \sigma σ和当前梯度的加权方均根(第一个时间点, σ 0 就 是 第 一 个 算 出 来 的 g r a d i e n t 值 \sigma^0就是第一个算出来的gradient值 σ0gradient

w t + 1 = w t − η σ t g t w^{t+1}=w^t-\frac{\eta}{\sigma^t}g^t wt+1=wtσtηgt

σ t = α ( σ t − 1 ) 2 + ( 1 − α ) ( g t ) 2 \sigma^t=\sqrt{\alpha(\sigma^{t-1})^2+(1-\alpha)(g^t)^2} σt=α(σt1)2+(1α)(gt)2

这里的 α \alpha α是可以自由调整的,RMSProp跟Adagrad不同之处在于

  • Adagrad的分母是对过程中所有的gradient取平方和开根号,就是说Adagrad考虑的是整个过程平均的gradient信息
  • RMSProp虽然也是对所有的gradient进行平方和开根号,但是它用一个 α \alpha α来调整对不同gradient的使用程度,比如你把α的值设的小一点,意思就是你更倾向于相信新的gradient所告诉你的error surface的平滑或陡峭程度,而比较无视于旧的gradient所提供给你的information
    在这里插入图片描述
    所以当你做RMSProp的时候,一样是在算gradient的root mean square,但是你可以给现在已经看到的gradient比较大的weight,给过去看到的gradient比较小的weight,来调整对gradient信息的使用程度
Momentum

除了learning rate的问题以外,在做deep learning的时候,也会出现卡在local minimum、saddle point或是plateau的地方,很多人都会担心,deep learning这么复杂的model,可能非常容易就会被卡住了

但是一旦出现local minima,它就必须在每一个dimension都是下图中这种山谷的低谷形状,假设山谷的低谷出现的概率为p,由于我们的network有非常非常多的参数,这里假设有1000个参数,每一个参数都要位于山谷的低谷之处,这件事发生的概率为 p 1000 p^{1000} p1000,当你的network越复杂,参数越多,这件事发生的概率就越低
在这里插入图片描述
所以在一个很大的neural network里面,其实并没有那么多的local minima,搞不好它看起来其实是很平滑的,所以当你走到一个你觉得是local minima的地方被卡住了,那它八成就是global minima,或者是很接近global minima的地方

where is Momentum from

有一个heuristic(启发性)的方法可以稍微处理一下上面所说的“卡住”的问题,它的灵感来自于真实世界,所以我们要做的,就是把惯性塞到gradient descent里面,这件事情就叫做Momentum

how to do Momentum

当我们在gradient descent里加上Momentum的时候,每一次update的方向,不再只考虑gradient的方向,还要考虑上一次update的方向,那这里我们就用一个变量 v v v去记录前一个时间点update的方向

随机选一个初始值 θ 0 \theta^0 θ0初始化 v 0 = 0 v^0=0 v0=0,接下来计算 θ 0 \theta^0 θ0处的gradient,然后我们要移动的方向是由前一个时间点的移动方向 v 0 v^0 v0和gradient的反方向 ▽ L ( θ 0 ) \triangledown L(\theta^0) L(θ0)来决定,即:

v 1 = λ v 0 − η ▽ L ( θ 0 ) v^1=\lambda v^0-\eta\triangledown L(\theta^0) v1=λv0ηL(θ0)

*此处的 λ \lambda λ也是一个手动调整的参数,表示惯性对前进方向的影响

接下来我们第二个时间点要走的方向 v 2 v^2 v2,它是由第一个时间点移动的方向 v 1 v^1 v1和gradient的反方向 ▽ L ( θ 1 ) \triangledown L(\theta^1) L(θ1)共同决定的; λ v \lambda v λv是图中的绿色虚线,它代表由于上一次的惯性想要继续走的方向; η ▽ L ( θ ) \eta\triangledown L(\theta) ηL(θ)是图中的红色虚线,它代表这次gradient告诉你所要移动的方向;它们的矢量和就是这一次真实移动的方向,为蓝色实线
在这里插入图片描述

Adam

其实RMSProp加上Momentum,就可以得到Adam

根据下面的paper来快速描述一下Adam的algorithm:

  • 先初始化 m 0 = 0 m^0=0 m0=0 m 0 m_0 m0就是Momentum中,前一个时间点的movement
    再初始化 v 0 = 0 v_0=0 v0=0 v 0 v_0 v0就是RMSProp中计算gradient的root mean square的 σ \sigma σ
    最后初始化 t = 0 t=0 t=0 t t t用来表示时间点
  • 先算出gradient g t = ▽ θ f t ( θ t − 1 ) g^t=\triangledown_{\theta}f_t(\theta_{t-1}) gt=θft(θt1)
  • 再根据过去要走的方向 m t − 1 m_{t-1} mt1和gradient g t g^t gt,算出现在要走的方向 m t m^t mt——Momentum

m t = β 1 m t − 1 + ( 1 − β 1 ) g t m_t=\beta_1m_{t-1}+(1-\beta_1)g_t mt=β1mt1+(1β1)gt

  • 然后根据前一个时间点的 v t − 1 v_{t-1} vt1和gradient g t g^t gt的平方,计算后放在分母的 v t v_t vt——RMSProp

v t = β 2 v t − 1 + ( 1 − β 2 ) g t 2 v_t=\beta_2v_{t-1}+(1-\beta_2)g_t^2 vt=β2vt1+(1β2)gt2

  • 接下来做了一个原来RMSProp和Momentum里没有的东西,就是bias correction,它使 m t m_t mt v t v_t vt都除上一个值,这个值本来比较小,后来会越来越接近于1

m ^ t = m t 1 − β 1 t \hat{m}_t=\frac{m_t}{1-\beta^t_1} m^t=1β1tmt

v ^ t = v t 1 − β 2 t \hat{v}_t=\frac{v_t}{1-\beta^t_2} v^t=1β2tvt

  • 最后做update,把Momentum建议你的方向 m ^ t \hat{m}_t m^t乘上learning rate α \alpha α,再除掉RMSProp normalize后建议的learning rate分母,得到update的方向

θ t = θ t − 1 − α ⋅ m ^ t v ^ t + ϵ \theta_t=\theta_{t-1}-\frac{\alpha\cdot\hat{m}_t}{\sqrt{\hat{v}_t}+\epsilon} θt=θt1v^t +ϵαm^t
在这里插入图片描述

Improve performance on Testing Data

这一部分主要讲述如何在Testing data上得到更好的performance,分为三个模块,Early Stopping、Regularization和Dropout
在这里插入图片描述

Early Stopping

假如你知道testing data上的loss变化情况,你会在testing set的loss最小的时候停下来,而不是在training set的loss最小的时候停下来;但testing set实际上是未知的东西,所以我们需要用validation set来替代它去做这件事情
在这里插入图片描述
注:很多时候,我们所讲的“testing set”并不是指代那个未知的数据集,而是一些已知的被你拿来做测试之用的数据集,比如kaggle上的public set,或者是你自己切出来的validation set

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参数集 θ \theta θ里的每一个参数都取平方然后求和,这件事被称作L2 regularization,即

L 2 r e g u l a r i z a t i o n : ∣ ∣ θ ∣ ∣ 2 = ( w 1 ) 2 + ( w 2 ) 2 + . . . L2 regularization:||\theta||_2=(w_1)^2+(w_2)^2+... L2regularization:θ2=(w1)2+(w2)2+...
在这里插入图片描述
通常我们在做regularization的时候,新加的term里是不会考虑bias这一项的,因为加regularization的目的是为了让我们的function更平滑,而bias通常是跟function的平滑程度没有关系的

L2 regularization的具体工作流程:

  • 加上regularization term之后得到一个新的loss function: L ′ ( θ ) = L ( θ ) + 1 2 λ ∣ ∣ θ ∣ ∣ 2 L'(\theta)=L(\theta)+\frac{1}{2}\lambda||\theta||_2 L(θ)=L(θ)+21λθ2
  • 将这个loss function对参数 w i w_i wi求微分: ∂ L ′ ∂ w i = ∂ L ∂ w i + λ w i \frac{\partial L'}{\partial w_i}=\frac{\partial L}{\partial w_i}+\lambda w_i wiL=wiL+λwi
  • 然后update参数 w i w_i wi w i t + 1 = w i t − η ∂ L ′ ∂ w i = w i t − η ( ∂ L ∂ w i + λ w i t ) = ( 1 − η λ ) w i t − η ∂ L ∂ w i w_i^{t+1}=w_i^t-\eta\frac{\partial L'}{\partial w_i}=w_i^t-\eta(\frac{\partial L}{\partial w_i}+\lambda w_i^t)=(1-\eta\lambda)w_i^t-\eta\frac{\partial L}{\partial w_i} wit+1=witηwiL=witη(wiL+λwit)=(1ηλ)witηwiL
    在这里插入图片描述

如果把这个推导出来的式子和原式作比较,你会发现参数 w i w_i wi在每一次update之前,都会乘上一个 ( 1 − η λ ) (1-\eta\lambda) (1ηλ),而 η \eta η λ \lambda λ通常会被设为一个很小的值, ( 1 − η λ ) (1-\eta\lambda) (1ηλ)通常是一个接近于1的值,比如0.99;也就是说,regularization做的事情是每次update参数 w i w_i wi之前,就先对原来的 w i − 1 w_{i-1} wi1乘个0.99,这意味着随着update的次数增加,参数 w i w_i wi会越来越接近于0

  • Q:你可能会问,要是所有的参数 w i w_i wi都越来越靠近0,那最后岂不是通通变成0,得到的network还有什么用?
    – A:其实不会出现最后所有参数都变为0的情况,因为通过微分得到的 η ∂ L ∂ w i \eta\frac{\partial L}{\partial w_i} ηwiL这一项是会和前面 ( 1 − η λ ) w i t (1-\eta\lambda)w_i^t (1ηλ)wit这一项最后取得平衡的

使用L2 regularization可以让weight每次都变得更小一点,这就叫做Weight Decay(权重衰减)

L1 regularization

除了L2 regularization中使用平方项作为new term之外,还可以使用L1 regularization,把平方项换成每一个参数的绝对值,即

∣ ∣ θ ∣ ∣ 1 = ∣ w 1 ∣ + ∣ w 2 ∣ + ∣ w 3 ∣ + . . . ||\theta||_1=|w_1|+|w_2|+|w_3|+... θ1=w1+w2+w3+...

  • 绝对值不能微分啊,该怎么处理呢?
    –实际上绝对值就是一个V字形的函数,在V的左边微分值是-1,在V的右边微分值是1,只有在0的地方是不能微分的,那真的走到0的时候就胡乱给它一个值,比如0,就ok了

如果w是正的,那微分出来就是+1,如果w是负的,那微分出来就是-1,所以这边写了一个w的sign function,它的意思是说,如果w是正数的话,这个function output就是+1,w是负数的话,这个function output就是-1

L1 regularization的工作流程如下:

  • 加上regularization term之后得到一个新的loss function: L ′ ( θ ) = L ( θ ) + 1 2 λ ∣ ∣ θ ∣ ∣ 1 L'(\theta)=L(\theta)+\frac{1}{2}\lambda||\theta||_1 L(θ)=L(θ)+21λθ1
  • 将这个loss function对参数 w i w_i wi求微分: ∂ L ′ ∂ w i = ∂ L ∂ w i + λ s g n ( w i ) \frac{\partial L'}{\partial w_i}=\frac{\partial L}{\partial w_i}+\lambda sgn(w_i) wiL=wiL+λsgn(wi)
  • 然后update参数 w i w_i wi w i t + 1 = w i t − η ∂ L ′ ∂ w i = w i t − η ( ∂ L ∂ w i + λ s g n ( w i ) ) = w i t − η ∂ L ∂ w i − η λ s g n ( w i ) w_i^{t+1}=w_i^t-\eta\frac{\partial L'}{\partial w_i}=w_i^t-\eta(\frac{\partial L}{\partial w_i}+\lambda sgn(w_i))=w_i^t-\eta\frac{\partial L}{\partial w_i}-\eta\lambda sgn(w_i) wit+1=witηwiL=witη(wiL+λsgn(wi))=witηwiLηλsgn(wi)
    在这里插入图片描述
    每次update的时候,不管三七二十一都要减去一个 η λ s g n ( w i ) \eta\lambda sgn(w_i) ηλsgn(wi) ,如果w是正的,sgn是+1,就会变成减一个positive的值让你的参数变小;如果w是负的,sgn是-1,就会变成加一个值让你的参数变大;总之就是让它们的绝对值减小至接近于0
L1 V.s. L2

对比一下L1和L2的update过程:

  • L 1 : w i t + 1 = w i t − η ∂ L ∂ w i − η λ s g n ( w i ) L1:w_i^{t+1}=w_i^t-\eta\frac{\partial L}{\partial w_i}-\eta\lambda sgn(w_i) L1:wit+1=witηwiLηλsgn(wi)
  • L 2 : w i t + 1 = ( 1 − η λ ) w i t − η ∂ L ∂ w i L2:w_i^{t+1}=(1-\eta\lambda)w_i^t-\eta\frac{\partial L}{\partial w_i} L2:wit+1=(1ηλ)witηwiL

L1和L2,虽然它们同样是让参数的绝对值变小,但它们做的事情其实略有不同:

  • L1使参数绝对值变小的方式是每次update减掉一个固定的值
  • L2使参数绝对值变小的方式是每次update乘上一个小于1的固定值

因此,当参数w的绝对值比较大的时候,L2会让w下降得更快,而L1每次update只让w减去一个固定的值,train完以后可能还会有很多比较大的参数;当参数w的绝对值比较小的时候,L2的下降速度就会变得很慢,train出来的参数平均都是比较小的,而L1每次下降一个固定的value,train出来的参数是比较sparse的,这些参数有很多是接近0的值,也会有很大的值

在之前所讲的CNN的task里,用L1做出来的效果是比较合适的,是比较sparse的

Weight Decay

实际上我们在人脑里面也会做Weight Decay

下图分别描述了,刚出生的时候,婴儿的神经是比较稀疏的;6岁的时候,就会有很多很多的神经;但是到14岁的时候,神经间的连接又减少了,所以neural network也会跟我们人有一些很类似的事情,如果有一些weight你都没有去update它,那它每次都会越来越小,最后就接近0然后不见了
在这里插入图片描述

some tips

在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里面去

Dropout

How to do 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)

当你在training的时候使用dropout,得到的performance其实是会变差的,因为某些neuron在training的时候莫名其妙就会消失不见,但这并不是问题,因为:

Dropout真正要做的事情,就是要让你在training set上的结果变差,但是在testing set上的结果是变好的
在这里插入图片描述
所以如果你今天遇到的问题是在training set上得到的performance不够好,你再加dropout,就只会越做越差;这告诉我们,不同的problem需要用不同的方法去解决,而不是胡乱使用,dropout就是针对testing set的方法,当然不能够拿来解决training set上的问题啦!

Testing

在使用dropout方法做testing的时候要注意两件事情:

  • testing的时候不做dropout,所有的neuron都要被用到
  • 假设在training的时候,dropout rate是p%,从training data中被learn出来的所有weight都要乘上(1-p%)才能被当做testing的weight使用
    在这里插入图片描述
Why Dropout?

neural network里面的每一个neuron就是一个学生,那大家被连接在一起就是大家听到说要组队做final project,那在一个团队里总是有人会拖后腿,就是他会dropout,所以假设你觉得自己的队友会dropout,这个时候你就会想要好好做,然后去carry这个队友,这就是training的过程

那实际在testing的时候,其实大家都有好好做,没有人需要被carry,由于每个人都比一般情况下更努力,所以得到的结果会是更好的,这也就是testing的时候不做dropout的原因
在这里插入图片描述

为什么training和testing使用的weight是不一样的呢?

假设现在的dropout rate是50%,那在training的时候,你总是期望每次update之前会丢掉一半的neuron,就像下图左侧所示,在这种情况下你learn好了一组weight参数,然后拿去testing

但是在testing的时候是没有dropout的,所以如果testing使用的是和training同一组weight,那左侧得到的output z z z和右侧得到的output z ′ z' z,它们的值其实是会相差两倍的,即 z ′ ≈ 2 z z'\approx 2z z2z,这样会造成testing的结果与training的结果并不match,最终的performance反而会变差
在这里插入图片描述
那这个时候,你就需要把右侧testing中所有的weight乘上0.5,然后做normalization,这样 z z z就会等于 z ′ z' z,使得testing的结果与training的结果是比较match的

Dropout is a kind of ensemble

dropout是一种终极的ensemble的方法

ensemble精神的解释

ensemble的方法在比赛的时候经常用得到,它的意思是说,我们有一个很大的training set,那你每次都只从这个training set里面sample一部分的data出来,像下图一样,抽取了set1,set2,set3,set4
在这里插入图片描述
我们之前在讲bias和variance的trade off的时候说过,打靶有两种情况:

  • 一种是因为bias大而导致打不准(参数过少)
  • 另一种是因为variance大而导致打不准(参数过多)

假设我们今天有一个很复杂的model,它往往是bias比较准,但variance很大的情况,如果你有很多个笨重复杂的model,虽然它们的variance都很大,但最后平均起来,结果往往就会很准

所以ensemble做的事情,就是利用这个特性,我们从原来的training data里面sample出很多subset,然后train很多个model,每一个model的structure甚至都可以不一样;在testing的时候,丢了一笔testing data进来,使它通过所有的model,得到一大堆的结果,然后把这些结果平均起来当做最后的output
在这里插入图片描述
如果你的model很复杂,这一招往往是很有用的,那著名的random forest(随机森林)也是实践这个精神的一个方法,也就是如果你用一个decision tree,它就会很弱,也很容易overfitting,而如果采用random forest,它就没有那么容易overfitting

为什么dropout是一个终极的ensemble方法呢?

在training network的时候,每次拿一个minibatch出来就做一次update,而根据dropout的特性,每次update之前都要对所有的neuron进行sample,因此每一个minibatch所训练的network都是不同的

假设我们有M个neuron,每个neuron都有可能drop或不drop,所以总共可能的network数量有 2 M 2^M 2M,个;所以当你在做dropout的时候,相当于是在用很多个minibatch分别去训练很多个network(一个minibatch一般设置为100笔data),由于update次数是有限的,所以做了几次update,就相当于train了几个不同的network,最多可以训练到 2 M 2^M 2M个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的做法

那按照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(近似)的
在这里插入图片描述

举例说明dropout和ensemble的关系

我们train一个下图右上角所示的简单的network,它只有一个neuron,activation function是linear的,并且不考虑bias,这个network经过dropout训练以后得到的参数分别为 w 1 , w 2 w_1,w_2 w1,w2,那给它input x 1 , x 2 x_1,x_2 x1,x2,得到的output就是 z = w 1 x 1 + w 2 x 2 z=w_1x_1+w_2x_2 z=w1x1+w2x2

如果我们今天要做ensemble的话,theoretically就是像下图这么做,每一个neuron都有可能被drop或不drop,这里只有两个input的neuron,所以我们一共可以得到2^2=4种network

我们手上这笔testing data x 1 , x 2 x_1,x_2 x1,x2,丢到这四个network中,分别得到4个output: w 1 x 1 + w 2 x 2 , w 1 x 1 , w 2 x 2 , 0 w_1x_1+w_2x_2,w_1x_1,w_2x_2,0 w1x1+w2x2,w1x1,w2x2,0,然后根据ensemble的精神,把这四个network的output通通都average起来,得到的结果是 1 2 ( w 1 x 1 + w 2 x 2 ) \frac{1}{2}(w_1x_1+w_2x_2) 21(w1x1+w2x2)

那根据dropout的想法,我们把从training中得到的参数 w 1 , w 2 w_1,w_2 w1,w2乘上(1-50%),作为testing network里的参数,也就是 w 1 ′ , w 2 ′ = ( 1 − 50 ( w 1 , w 2 ) = 0.5 w 1 , 0.5 w 2 w_1',w_2'=(1-50%) (w_1,w_2)=0.5w_1,0.5w_2 w1,w2=(150(w1,w2)=0.5w1,0.5w2
在这里插入图片描述
这边想要呈现的是,在这个最简单的case里面,用不同的network structure做ensemble这件事情,跟我们用一整个network,并且把weight乘上一个值而不做ensemble所得到的output,其实是一样的

值得注意的是,只有是linear的network,才会得到上述的等价关系,如果network是非linear的,ensemble和dropout是不equivalent的;但是,dropout最后一个很神奇的地方是,虽然在non-linear的情况下,它是跟ensemble不相等的,但最后的结果还是会work

如果network很接近linear的话,dropout所得到的performance会比较好,而ReLU和Maxout的network相对来说是比较接近于linear的,所以我们通常会把含有ReLU或Maxout的network与Dropout配合起来使用

参考

https://sakura-gh.github.io/ML-notes/ML-notes-html/13_Tips-for-Deep-Learning.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值