天天看点

Dropout深入理解

文章目录

    • 简介
    • What is dropout?
    • How it works?
    • Dropout in neural networks
      • Training stage
      • Test stage
    • Code implementation
    • Some questions
    • References

简介

在2012年,Alex、Hinton(大佬们呀)在其论文《ImageNet Classification with Deep Convolutional Neural Networks》中用到了Dropout算法,用于防止过拟合。并且,这篇论文提到的AlexNet网络模型引爆了神经网络应用热潮,并赢得了2012年图像识别大赛冠军,使得CNN成为图像分类上的核心算法模型。部分摘自博客。

首先我们从神经网络训练的两个难题说起:

  • 费事
  • 易过拟合

这两个缺点真是抱在深度学习大腿上的两个大包袱,一左一右,相得益彰,额不,臭气相投。过拟合是很多机器学习的通病,过拟合了,得到的模型基本就废了。而为了解决过拟合问题,一般会采用ensemble方法,即训练多个模型做组合,此时,费时就成为一个大问题,不仅训练起来费时,测试起来多个模型也很费时。总之,几乎形成了一个死锁。

Dropout的出现很好的可以解决这个问题,并在一定程度上达到正则化的效果。

What is dropout?

那么什么是Dropout呢?

Dropout是CNN中防止过拟合提高效果的一个大杀器。众所周知,在训练深度学习模型时,如果模型的参数太多,而训练样本又太少,训练出来的模型很容易产生过拟合的现象。过拟合具体表现在:模型在训练数据上损失函数较小,预测准确率较高;但是在测试数据上损失函数比较大,预测准确率较低。

Dropout可以作为训练深度神经网络的一种trick供选择。在每个训练批次(batch)中,通过忽略一半的特征检测器(让一半的隐层节点值为0),可以明显地减少过拟合现象。这种方式可以减少特征检测器(隐层节点)间的相互作用(即减弱神经元节点间的联合适应性,增强了泛化能力。),检测器相互作用是指某些检测器依赖其他检测器才能发挥作用。

Dropout说的简单一点就是:我们在前向传播的时候,让某个神经元的激活值以一定的概率p停止工作,这样可以使模型泛化性更强,因为它不会太依赖某些局部的特征(或者说不会太依赖于某几个局部特征的相互作用模型才起作用),如下所示:

Dropout深入理解

对于神经网络单元,按照一定的概率将其暂时从网络中丢弃。注意是暂时,对于随机梯度下降来说,由于是随机丢弃,故而每一个mini-batch都在训练不同的网络。因而,对于一个有N个节点的神经网络,有了dropout后,就可以看做是 2 n 2^n 2n个模型的集合了,但此时要训练的参数数目却是不变的,这就解脱了费时的问题。(解决过拟合和费时问题的直观理解)

How it works?

假设我们要训练这样一个神经网络,如下:

Dropout深入理解
Dropout深入理解

输入是x输出是y,正常的流程是:我们首先把x通过网络前向传播,然后把误差反向传播以决定如何更新参数让网络进行学习。使用Dropout之后,过程变成如下:

  1. 首先随机(暂时)删掉网络中一半(比例是个超参)的隐藏神经元,输入输出神经元保持不变(下图中虚线为部分临时被删除的神经元)
    Dropout深入理解
  2. 然后把输入x通过修改后的网络前向传播,然后把得到的损失结果通过修改的网络反向传播。一小批训练样本(batch)执行完这个过程后,在没有被删除的神经元上(即在上图的网络中)按照随机梯度下降法更新对应的参数(w,b)。
  3. 然后继续重复这一过程:
    • 恢复被删掉的神经元(此时被删除的神经元保持原样,而没有被删除的神经元已经有所更新)
    • 从隐藏层神经元中随机选择一个一定比例(如50%)的子集临时删除掉(备份被删除神经元的参数)。
    • 对一小批训练样本,先前向传播然后反向传播损失并根据随机梯度下降法更新参数(w,b) (没有被删除的那一部分参数得到更新,删除的神经元参数保持被删除前的结果)。
    不断重复这一过程。

Dropout in neural networks

Dropout的具体工作流程上面已经介绍完了,那么上述操作具体是如何实现的呢?如何用代码实现dropout呢?

而为了达到ensemble的特性,有了dropout后,神经网络的训练和预测就会发生一些变化。下面,我们来具体讲解一下Dropout代码层面的一些公式推导及代码实现思路。

Training stage

无可避免的,在训练网络的每个单元都要添加一道概率流程。如下:

Dropout深入理解

对应的公式变化如下:

  • 没有dropout的神经网络:

    z i ( l + 1 ) = w i ( l + 1 ) y l + b i ( l + 1 ) z_{i}^{(l+1)} =\mathbf{w}_{i}^{(l+1)} \mathbf{y}^{l}+b_{i}^{(l+1)} zi(l+1)​=wi(l+1)​yl+bi(l+1)​

    y i ( l + 1 ) = f ( z i ( l + 1 ) ) y_{i}^{(l+1)} =f\left(z_{i}^{(l+1)}\right) yi(l+1)​=f(zi(l+1)​)

  • 有dropout的神经网络:

    r j ( l ) ∼ Bernoulli ⁡ ( p ) r_{j}^{(l)} \sim \operatorname{Bernoulli}(p) rj(l)​∼Bernoulli(p)

    y ~ ( l ) = r ( l ) ∗ y ( l ) \tilde{\mathbf{y}}^{(l)} =\mathbf{r}^{(l)} * \mathbf{y}^{(l)} y~​(l)=r(l)∗y(l)

    z i ( l + 1 ) = w i ( l + 1 ) y ~ l + b i ( l + 1 ) z_{i}^{(l+1)} =\mathbf{w}_{i}^{(l+1)} \widetilde{\mathbf{y}}^{l}+b_{i}^{(l+1)} zi(l+1)​=wi(l+1)​y

    ​l+bi(l+1)​

    y i ( l + 1 ) = f ( z i ( l + 1 ) ) y_{i}^{(l+1)} =f\left(z_{i}^{(l+1)}\right) yi(l+1)​=f(zi(l+1)​)

上面公式中Bernoulli函数是为了生成概率r向量,也就是随机生成一个0、1的向量。

代码层面实现让某个神经元以概率p停止工作(失活),其实就是让它的激活函数输出值以概率p变为0。比如我们某一层网络神经元的个数为1000个,其激活函数输出值为 y 1 , y 2 , y 3 , . . . . . . , y 1000 y_1, y_2, y_3, ......, y_{1000} y1​,y2​,y3​,......,y1000​,我们dropout比率选择0.4,那么这一层神经元经过dropout后,1000个神经元中会有大约400个的值被置为0。(一定是大约400个)

注:经过上面屏蔽掉某些神经元,使其激活值为0以后,我们还需要对向量 y 1 , y 2 , y 3 , . . . . . . , y 1000 y_1, y_2, y_3, ......, y_{1000} y1​,y2​,y3​,......,y1000​进行缩放,也就是乘以 1 / ( 1 − p ) 1/(1-p) 1/(1−p)(其实 p p p为丢弃概率,那么 ( 1 − p ) (1-p) (1−p)就为保留概率)。如果你在训练的时候,经过置0后,没有对 y 1 , y 2 , y 3 , . . . . . . , y 1000 y_1, y_2, y_3, ......, y_{1000} y1​,y2​,y3​,......,y1000​进行缩放(rescale),那么在测试的时候,就需要对权重进行缩放。

注:在训练阶段,对某一层的激活输出值进行dropout操作后(此时p为丢弃概率,那么1-p就为保留概率),为了保证训练和测试阶段,某一层通过的信息量大小是一定的(自己理解)。可以通过两种方法来实现:

  1. 在训练的时候,经过置0后,对 y 1 , y 2 , y 3 , . . . . . . , y 1000 y_1, y_2, y_3, ......, y_{1000} y1​,y2​,y3​,......,y1000​进行缩放(即除以 ( 1 − p ) (1-p) (1−p)),这样做的目的是:经过缩放后,此时训练过程中某层每个神经元激活值的输出期望为: E ( x ) = ( 1 − p ) ( y / ( 1 − p ) ) + p ∗ 0 = y E(x) = (1-p)(y/(1-p)) + p * 0 = y E(x)=(1−p)(y/(1−p))+p∗0=y,因此测试(或预测)阶段就不再需要特殊处理了。(后面的代码示例就是用的这种方式)
  2. 如果在训练的时候,经过置0后,没有对 y 1 , y 2 , y 3 , . . . . . . , y 1000 y_1, y_2, y_3, ......, y_{1000} y1​,y2​,y3​,......,y1000​进行缩放(rescale),那么在测试的时候,就需要对权重进行缩放(乘以失活率p)。此操作如下图所示:

Test stage

预测模型的时候,每一个神经单元的权重参数要乘以概率p。(如果训练阶段没有做缩放的话,否则不需要这一步)

Dropout深入理解

测试阶段Dropout公式为:

w t e s t ( l ) = p W ( l ) w_{test}^{(l)} = pW^{(l)} wtest(l)​=pW(l)

Code implementation

dropout示例代码如下:

# coding:utf-8
import numpy as np
 
# dropout函数的实现
def dropout(x, level):
    if level < 0. or level >= 1: #level是概率值,必须在0~1之间
        raise ValueError('Dropout level must be in interval [0, 1[.')
    retain_prob = 1. - level  # 0.6
 
    # 我们通过binomial函数,生成与x一样的维数向量。binomial函数就像抛硬币一样,我们可以把每个神经元当做抛硬币一样
    # 硬币 正面的概率为p,n表示每个神经元试验的次数
    # 因为我们每个神经元只需要抛一次就可以了所以n=1,size参数是我们有多少个硬币。
    random_tensor = np.random.binomial(n=1, p=retain_prob, size=x.shape) #即将生成一个0、1分布的向量,0表示这个神经元被屏蔽,不工作了,也就是dropout了
    print('random_tensor:', random_tensor)
    print()
 
    x *= random_tensor
    print('dropoutted:', x)
    
    x /= retain_prob   # 缩放操作:dropout后的数据再除以一个保留概率(1 - 丢弃概率)
    return x
 
#对dropout的测试,大家可以跑一下上面的函数,了解一个输入x向量,经过dropout的结果  
x=np.asarray([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], dtype=np.float32)
print('x: ', x)
dropout(x, 0.4)
           

运行结果如下所示,想必现在大家应该都很清楚了吧。。。

Dropout深入理解

另一个版本:

Dropout深入理解

Some questions

  1. 取平均的作用: 先回到标准的模型即没有dropout,我们用相同的训练数据去训练5个不同的神经网络,一般会得到5个不同的结果,此时我们可以采用 “5个结果取均值”或者“多数取胜的投票策略”去决定最终结果。例如3个网络判断结果为数字9,那么很有可能真正的结果就是数字9,其它两个网络给出了错误结果。这种“综合起来取平均”的策略通常可以有效防止过拟合问题。因为不同的网络可能产生不同的过拟合,取平均则有可能让一些“相反的”拟合互相抵消。dropout掉不同的隐藏神经元就类似在训练不同的网络,随机删掉一半隐藏神经元导致网络结构已经不同,整个dropout过程就相当于对很多个不同的神经网络取平均。而不同的网络产生不同的过拟合,一些互为“反向”的拟合相互抵消就可以达到整体上减少过拟合。
  2. 减少神经元之间复杂的共适应关系: 因为dropout程序导致两个神经元不一定每次都在一个dropout网络中出现。这样权值的更新不再依赖于有固定关系的隐含节点的共同作用,阻止了某些特征仅仅在其它特定特征下才有效果的情况 。迫使网络去学习更加鲁棒的特征 ,这些特征在其它的神经元的随机子集中也存在。换句话说假如我们的神经网络是在做出某种预测,它不应该对一些特定的线索片段太过敏感,即使丢失特定的线索,它也应该可以从众多其它线索中学习一些共同的特征。从这个角度看dropout就有点像L1,L2正则,减少权重使得网络对丢失特定神经元连接的鲁棒性提高。
  3. Dropout类似于性别在生物进化中的角色: 虽然直观上看dropout是ensemble在分类性能上的一个近似,然而实际中,dropout毕竟还是在一个神经网络上进行的,只训练出了一套模型参数。在自然界中,在中大型动物中,一般是有性繁殖,有性繁殖是指后代的基因从父母两方各继承一半。但是从直观上看,似乎无性繁殖更加合理,因为无性繁殖可以保留大段大段的优秀基因。而有性繁殖则将基因随机拆了又拆,破坏了大段基因的联合适应性。但是有性繁殖的方式不仅仅可以将优秀的基因传下来,还可以降低基因之间的联合适应性,使得复杂的大段大段基因联合适应性变成比较小的一个一个小段基因的联合适应性。dropout也能达到同样的效果,它强迫一个神经单元,和随机挑选出来的其他神经单元共同工作,达到好的效果。消除减弱了神经元节点间的联合适应性,增强了泛化能力。

再次特别感谢大佬博客。

done~

References

  • https://blog.csdn.net/stdcoutzyx/article/details/49022443
  • https://blog.csdn.net/program_developer/article/details/80737724#commentsedit
  • https://blog.csdn.net/hjimce/article/details/50413257
  • https://blog.csdn.net/stdcoutzyx/article/details/49022443
  • https://zhuanlan.zhihu.com/p/23178423
  • https://blog.csdn.net/qunnie_yi/article/details/80128463
  • https://blog.csdn.net/whiteinblue/article/details/37808623
  • https://www.cnblogs.com/tornadomeet/p/3258122.html?_t_t_t=0.09445037946091872
  • Hinton G E, Srivastava N, Krizhevsky A, et al. Improving neural networks by preventing co-adaptation of feature detectors[J]. arXiv preprint arXiv:1207.0580, 2012.

继续阅读