李宏毅深度学习笔记-深度学习技巧

深度学习的流程

image-20200601150042427

通过深度学习三部曲得到一个神经网络,接下来要做什么事情?

  1. 先检查神经网络在训练数据集上的结果好不好,不好则回头检查三部曲。过拟合在深度学习里面不是要先关注的问题,因为深度学习是一个不断迭代训练的模型,可能一开始训练精度很差,因此首先要考虑的是如何优化三部曲里面的东西。
  2. 训练精度好,再去检查测试精度,如果结果不好,再考虑过拟合。而且有时候使用新技术去优化过拟合,可能又会导致训练精度变差,这时候又要去检查训练精度。
  3. 训练精度和测试精度都好,才可以使用

image-20200601150850887

黄线是20层的神经网络,红线是56层的神经网络

是否会觉得56层神经网络效果差是由于过拟合?真的是这样吗?

在做test error的时候,先要去检查train error。有些方法不用做这种事,但是对于神经网络来说是要去做的。

有可能在训练数据上,56层的神经网络误差就很大。为什么会这样子?

可能有局部最小值、鞍点等种种问题,56层的神经网络可能卡在局部最小值,得到一组很差的参数。这个也不是欠拟合,因为56层本身参数量就很多。理论上20层神经网络能做到事情,56层神经网络也可以做到,只要前20层一样,后36层都是恒等式就可以。所以也不是欠拟合,就是没有训练好参数。像喷火龙一样,能力是够的,就是不想打。

image-20200601151833862

看到一个深度学习方法的时候,永远要先思考,这种方法用来解什么问题。

深度学习里有两个问题,一个是train set上不好,一个是test set上不好。一个方法不好的时候,往往针对其中一个问题来做处理。比如dropout,但是dropout是在test不好的时候用的,如何你train结果不好,再用dropout,只会导致train更差。

如何改进深度学习?

train 结果不好

新的激活函数

image-20200601152353439

train 结果不好的时候,考虑是否网络结构没有设计好。比如激活函数不好,因此换一些新的激活函数。

image-20200601155239537

1980年代比较常用的激活函数是sigmoid函数,为什么要用sigmoid?

在过去,会发现越深不一定意味着越好,如上图,layer越多,准确率会下降。可能会觉得是过拟合,但这个是train的结果。

梯度消失

image-20200601160354704

网络叠的很深的时候

  • 靠近input的layer,参数对loss function的微分会很小,靠近output的layer,参数对loss function的微分会很大。
  • 当设定同样的学习率时,靠近input的layer的参数update很慢,靠近output的layer的参数update很快
  • 几次迭代下来,在input那边的参数还没怎么变动(还是近似random值),output那边的参数已经收敛了,然后loss 下降的很慢,处于一个局部最小点

为什么结果很差?

因为output附近参数的收敛,几乎是基于input附近参数的随机值。output就相当于是随机的

image-20200601161539506

为什么会发生梯度消失?

直觉来想

image-20200601200704902

直觉的意思是说,对某个参数做个小小的变化,对cost的影响是怎么样,来看这个参数的梯度有多大

对第一个layer的某个参数\(+\Delta w\) ,即改变某个参数的权重,对某一个的神经元的output会有影响,但是影响是会衰减的。

为什么是衰减的?

看右上图是sigmoid的形状,sigmoid把\(-\infty\)\(+\infty\)压缩到0,1。就算input的变化很大,output的变化也会变得很小。所以就算\(\Delta w\)造成\(w\)有很大变化,经过sigmoid之后,output变化也会衰减,且每通过一层的sigmoid,变化就衰减一次。如果神经网络很深,变化衰减的次数越多,直到最后对最终output的影响非常小。

也就是说在input层附近改一下参数,output层附近的output变化是很小的,因此对cost的影响也很小,自然梯度值也很小。

如何处理梯度消失

image-20200601202437260

改一下激活函数,可能就可以处理这个问题

现在比较常用的就是ReLU激活函数,input>0时Input=output,input<0时output=0

选择ReLU有什么好处?

  • 跟sigmoid比起来,运算很快,sigmoid里面还有指数运算
  • 有一些生物上的原因
  • ReLU等同于无穷多不同bias的sigmoid叠加
  • 可以处理梯度消失问题

image-20200601202933597

ReLU如何处理梯度消失问题?

查看一个使用ReLU作为激活函数的神经网络

ReLU当input>0时input=output,是线性的,当input<0时output=0。对那些output=0的神经元来说,对网络是没有一点影响的,对最终的output没有一点作用,就可以把这些神经元忽略掉。

image-20200601203350363

剩下的网络里面神经元的input=output,整个网络就是一个瘦长的线性网络

刚才说过的output衰减是由于input通过sigmoid,但是线性网络就不会有衰减问题

使用RelU变成了线性网络,但是我们要的不是一个线性网络,做深度学习就是不想函数是线性的,我们希望得到一个复杂的非线性函数,那使用ReLU不会有问题吗?不会让函数变得很弱吗?

对整个网络来说,整体还是非线性的。虽然input变化一点,output变化是线性的,但如果input变化的比较多,直接变到<0了,那整个神经元就没有用了,或者从没有用变到线性,所以整体上还是非线性的。

Relu在0点不可微啊?

实际中可以不用管这个点,>0的时候微分为1,<0的时候微分为0

image-20200601204856343

ReLU有很多变种

  • input<0时微分=0,那就没办法update参数了,那么给input<0的微分为0.01,这个就是leaky ReLU
  • 为什么就用0.01,不用0.07,0.08,有人就设置一个参数\(\alpha\),这个参数可以从train 中学习到,甚至每个神经元都可以有一个不同的\(\alpha\)
  • Relu为什么是这个样子,有没有其他的样子,产生了Maxout,让网络自动学习激活函数,ReLU就是其中一个特例,即Maxout network 可以学出ReLU这样的激活函数,具体要取决于训练数据

image-20200601205741296

input乘以不同的权重得到5,7,-1,1,本来这些值是要通过激活函数的。在Maxout里面,把这些值group起来(哪些值被group是事先决定的),在group里面选择最大值作为output,这个跟max pool 是一样的。

把几个值组成一个group是超参数,可以3个,4个。

image-20200601210321056

Maxout是可以做到Relu的功能的

ReLU:上左下图看到,z和x是线性的,z<0时a=0,z>0时a=z

Maxout:上右上图看到,假设计算\(z_2\) 的两个w和b=0,那么\(z_2=0\)\(z_1\)和x的关系就是右下图蓝色线,\(z_2\)和x的关系是红色线,因为\(z_2=0\) 。Maxout是\(max\{z_1,z_2\}\)\(z_1>0\)时为\(z_1\)\(z_1<0\)时为\(z_2\) =0。只要把\(z_1\)\(w,b\)等于Relu里z的\(w,b\),那么两者作用就是相等的

image-20200601211534408

Maxout还可以做出不同的激活函数

\(w',b'\)不为0时,\(z_2\)\(x\)的关系是红色线,那么Maxout的作用是绿色这条线,得到一个不一样的激活函数,由\(w,b,w',b'\)决定,即是由训练数据学习的

image-20200601211845997

Maxout可以做出任意的分段凸激活函数

有多少个分段,取决于把多少个值组成一个group

image-20200601212032930

如何训练Maxout?有Max不能微分

假设比较大的是\(z_1^1\),等于\(a_1^1\)\(z_2^2=a_1^2\)

\(z_4^1=a_2^1;z_3^2=a_2^2\)

所以Max操作就是一个线性操作,只不过接的是前面group里较大的元素。那没有被接到的元素就没用了,可以去掉。

image-20200601212600190

所以训练Maxout就相当训练一个细长的线性网络的参数,这些参数对应到group里面较大的元素

这里会有一个问题,没有被选择的元素对应的权重怎么训练?

这其实不是一个问题,因为不同的input,\(z_1^1,z_4^1,z_2^2,z_3^2\)是不同的,每次输入Input时,网络结构都是不一样的。如果有很多训练数据,每个权重都可以被训练到。

自适应学习率

image-20200601213255684

Adagrad每个权重有一个学习率,t+1次迭代的学习率等于 \(\eta\) 除以之前所有的梯度平方和

\(w_1\)方向上梯度小,变化缓慢,那么给大的学习率;在\(w_2\)方向上梯度大,变化剧烈,那么给小的学习率

image-20200601213756798

实际问题中,loss 不会是凸的,有各种奇怪的形状,比如上图这种月形

所有有可能在\(w_1\)一个方向上,有的区域很平缓,需要一个大的学习率,有的区域很陡峭,则需要一个小的学习率

仅仅使用Adagrad是不够的,需要更动态的调整学习率的方法,于是提出RMSProp方法。

image-20200601214144990

固定的学习率\(\eta\) 除以 \(\sigma\)\(\sigma\)计算如上图所示,\(\alpha\)是人工调整的

原来Adagrad的分母是\(g^0,g^1,g^2...\)取平方和开根号

RMSProp的分母里,比如\(\sigma^2\)包含了\(g^2\),也包含了\(g^0,g^1\),因为\(\sigma^1\)\(g^0,g^1\)计算出来的

不过RMSProp分母里还乘上了一个权重\(\alpha\) 和(\(1-\alpha\)),如果手动把\(\alpha\)调整小一点,则倾向于相信新的梯度

RMSProp一样是在算梯度的均方根,但是可以给现在的梯度一个大的权重,给过去的梯度一个小的权重

image-20200602140309665

除了学习率的问题之外,也有其他问题,比如卡在局部极小点,鞍点和plateau(平稳区域)

Yann LeCun(CNN之父)提过,不用太担心局部最小值问题,在误差曲面上没有太多局部最小值。要是一个局部最小值,那在每个维度都必须是局部最小的形状(一个山谷的谷底),假设山谷谷底出现的概率是p,因为神经网络有很多的参数,假设有1000个参数,每个参数都要在谷底的概率是\(p^{1000}\) ,网络越大参数越多,出现的概率就越低,所以局部最小值在很大的神经网络里没有那么多,当训练走到一个认为是局部最小值的地方的时候,大概率是全局最小值或很接近全局最小值。

image-20200602141745856

一个启发式的方法,来处理下局部最小值、鞍点、平稳区域的问题。

在真实世界里,把球从上图左上角丢下去,滚到平稳区域有惯性不会停下来,滚到上坡的地方,如果坡不是很陡,可以翻过这个坡,就可以走到比局部最小值更好的地方。我们可以把惯性这个性质融合到梯度下降里去,这个就叫做动量。

image-20200602142236222

动量怎么做,先复习下一般的梯度下降。

选个参数初始值,计算梯度,参数往负梯度方向走一个步长\(\eta\)

重新计算梯度,参数走一个步长

再计算梯度,再走一个步长

直到梯度等于0或者趋近于0停止

image-20200602142506888

加上动量怎么做?

每一次移动的方向不再是只考虑梯度,而是现在的梯度方向加上前一个时间点移动的方向

选择一个初始值\(\theta^0\),用一个值\(v\) 记录前一个时间点移动的方向,初始的时候为\(v^0=0\)

计算\(\theta^0\)的梯度,上图红色箭头,现在移动的方向变为 \(v^1=\lambda v^0-\eta \Delta L(\theta^0)\),类似惯性

计算\(\theta^1\)的梯度,参数移动方向为\(v^2=\lambda v^1-\eta \Delta L(\theta^1)\)

image-20200602143145631

另一个角度来理解动量

在第i个时间点移动的量\(v^i\),是过去算出来的梯度总和

$v^0=0 $

\(v^1=-\eta \Delta L(\theta^0)\)

\(v^2=-\lambda \eta \Delta L(\theta^0)-\eta \Delta L(\theta^1)\),有\(\theta^0,\theta^1\)的梯度,只不过权重不一样,\(\lambda<0\)时,越之前的梯度权重越小,越在意现在的梯度,不过之前的梯度也对现在update的方向有一些影响

image-20200602152250654

加入动量后,每次移动的方向是负梯度+动量

动量很强的话,有一定可能跳出局部最小值

image-20200602152802836

RMSProp+Momentum 可以得到Adam

上图初始化里的\(m_0\)就是动量,\(v_0\)就是RMSProp里的\(\sigma\)

步骤里:

计算梯度\(g_t\)

根据\(g_t\)计算出\(m_t\) ,就是现在要走的方向,考虑过去要走的方向\(m_{t-1}\)+现在的梯度\(g_t\)

计算放在分母里的\(v_t\),是前一个时间点的\(v_{t-1}\)+现在的梯度平方\(g_t^2\)

然后计算RMSProp和Momentum没有的东西bias correction(偏差校正) \(\hat{m_t}\)\(\hat{v_t}\)

test 结果不好

提前停止

image-20200602153738504

上图的testing data不是测试集,而是验证集

image-20200602154337457

提前停止是什么意思?

随着训练次数变多,如果学习率比较适合的话,训练集总体损失是越来越小的。但是测试集和训练集的分布是不一样的,可能训练集总体损害减小,测试集总体损失反而变大。理想上,如果知道测试集总体损失的变化,那么训练应该停在测试损失最小的地方。但是实际上我们并不知道测试损失的情况,那么用验证集来检验这个事情。

用验证集模拟测试集,来做训练停止。

正则化

image-20200602155144704

image-20200602155204580

正则化重新定义了损失函数,原来的损失函数是\(L(\theta)\),再加上正则项,比如L2正则

加正则化项,一般不会考虑函数的偏差,因为加正则的目的是让函数变得更平滑,而偏差跟函数的平滑程度没有关系

image-20200602155643561

如果加入L2正则项,微分会有怎么样的结果。

新的损失函数为\(L'(\theta)=L(\theta)+\lambda \frac{1}{2}||\theta||_2\),求梯度看上图

参数更新的式子变为 \(\large w^{t+1}=(1-\eta \lambda)w^t-\eta \frac{\partial L}{\partial w}\)

每次更新参数,先把原来的参数乘以\(1-\eta \lambda\)\(\eta\)是学习率(一个很小的值),\(\lambda\)也是一个很小的值(比如0.001)。

那么\(1-\eta \lambda\)是一个很接近1的值(比如0.99),那么每次更新参数,就会把原来的参数缩小为0.99倍,参数会越来越接近于0,不一定越来越小,如果\(w\)是负的就是变大。

那越来越接近于0,不是所有参数都变为0了吗?

所有参数不会都变为0,因为还有后一项来平衡。

使用L2正则,每次都让参数变小一点,也叫做Weight Decay

正则化在深度学习的重要性不是很高,帮助往往没有特别显著,一个可能的原因是做了提前停止,我们可以决定什么时候停止训练,一般参数初始化都是一个很接近与0 的值,参数更新通常是离0越来越远,停止训练让参数更新次数变少,避免参数不会离0太远,正则化也是让参数不要离0太远,两者的作用就重叠了。

image-20200602161834493

现在看L1正则

出现一个问题,绝对值不能微分怎么办?

绝对值的图形是V,那么在一边的微分是-1,另一边的微分是1,不能微分的地方只有值是0的点,那就不要管这个点。如果\(w\)是正的,微分就是1,负的微分就是-1。

参数更新的式子里\(-\eta \lambda sgn(w^t)\)\(w\)是正的,就减去一个值让参数变小,\(w\)是负的,就加上一个值让参数变大,不管参数是多少。跟L2对比,当参数>0时,两者作用都是让参数变小,但是L2是乘以一个值(0.99),而L1是减去一个固定值。如果参数为100万,L2里乘以0.99相当于100万减去一个很大的值,对L1来说是减去一个固定值。所以对L2来说,一个很大的参数,下降速度也会很快,但是对L1来说参数是大是小下降速度不会改变,通过L1还会有一些很大的参数值。

考虑很小的值,比如0.1、0.01这种接近于0,通过L2下降速度就很慢,那就会保留很多接近于0的值。而通过L1,每次下降固定值,就不会保留很多很小的值。所以L1后是稀疏的(有很多接近0的值,也有很多很大的值),L2平均都比较小。

image-20200602164931658

人6岁的时候有很多的神经,14岁的时候神经变少了

加入正则化,因为权重是被动地接近0的,如果不去更新权重,就会变得越来越小,最后就不见了

dropout

image-20200602165302231

image-20200602165316950

dropout是怎么做的?

train 中每次更新参数之前,对每一个神经元(包括输入层的每个元素)采样,每个神经元以概率p被丢弃。

image-20200602200158664

被丢弃的神经元连接的权重也丢弃。采样后网络结构就变得很细长。

注意dropout在每次参数更新之前都要重新做一遍,所以每次train 的网络结构都不一样

train 做dropout,train的结果是会变差的,但是test 结果会变好,所以不适合train 结果不好的网络调优

image-20200602200607918

test 怎么做呢?

test的时候不做dropout,所有的神经元都要使用

假设train dropout rate是p%,那么在test的时候所有权重都要乘以\(1-p\%\)

image-20200602200903727

为什么dropout有用?

直觉的想法:

train的时候会丢弃一些神经元,就像练功的时候脚上绑重物,实际战斗的时候重物拿下来就会变得很强

image-20200602201101794

为什么dropout有用?

另外一个直觉的理由:

一个神经网络里的每个神经元都是一个学生,组在一起就是一个团队,团队里总有人会摆烂。

在train的时候假设队友会摆烂,test实际的时候每个人都在好好做,所以test结果更好

image-20200602201403459

为什么train和test用的权重不一样?

直觉理由:

假设dropout rate 是50%,那么期望总是会丢掉一半的神经元,在test的时候 \(z\) 会变大两倍。所以在test的时候把权重都乘以0.5,做一下规范化,这时候z 就会约等于 train 的z

image-20200602201814432

dropout有很多正式的解释

如果你有一个很复杂的model,往往是偏差小方差大,但是多个复杂model集成后方差会变小

dropout是一种终极的集成模型,每次训练都只是从训练集采样一部分,然后训练很多个model,每个model的结构都可以不一样

image-20200602202217695

test的时候就相当于使用了很多个model,然后结果平均起来。

想想随机森林。

image-20200602202342320

为什么说dropout是终极的集成模型?

每次更新参数之前,采样一个批次的数据,不同批次的网络不同。假设有M个神经元,每个神经元都可以丢弃或者不丢弃,所以可能的神经元批次有\(2^M\)种,总共有\(2^M\)种网络。例如一个神经网络使用100个数据,参数update几次,就有几个神经网络。

只使用100个数据训练,是否会有问题?

没有关系,因为不同的网络之间的参数是共享的,上图4个网络都有左下方的那个权重,那这个权重就是4个数据集合起来训练的结果。因为每次训练后,这个权重都被更新,只不过进行了4个批量梯度下降。

image-20200602203315704

test怎么从集成的角度解释?

训练数据使用所有的神经网络模型,最后平均每个模型的输出,但是因为模型太多,运算会很慢。

而dropout认为只要把所有的权重乘以\(1-p\%\) ,由一个模型的输出约等于之前集成模型的平均值

image-20200602203640826

为什么一个模型的输出约等于之前集成模型的平均值?

右上图所示,一个简单的神经元,激活函数是线性的,只有两个参数,不考虑偏差b

现在\(w_1,w_2\)是进过dropout训练后的参数值

做集成模型的话,理论上如上图左边所示,每个input可以被丢弃或不丢弃,那么总共有4种网络结构。

得到4个输出

\(z=w_1x_1+w_2x_2\)

\(z=w_2x_2\)

\(z=w_1x_1\)

\(z=0\)

4个输出平均后为\(\large z=\frac{1}{2}w_1x_1+\frac{1}{2}w_2x_2\),相当于对所有权重乘以1-p%不做集成的模型的输出

这里有趣的地方时只有激活函数为线性时才有以上结论,激活函数变为sigmoid或者其它非线性的函数,结果就不会相等了

也有个有趣的想法,就是如果激活函数使用的是接近于线性函数的比如ReLU和Maxout这种,那使用dropout效果就会比较好

posted @ 2020-06-02 20:52  yueqiudian  阅读(828)  评论(0)    收藏  举报