Dropout

作者: zelda2333 | 来源:发表于2020-05-22 19:28 被阅读0次

    1. Dropout简介

    1.1 前言

    在机器学习的模型中,如果模型的参数太多,而训练样本又太少,训练出来的模型很容易产生过拟合的现象。即:模型在训练数据上loss较小,预测准确率较高;但是在测试数据上loss比较大,预测准确率较低。 过拟合是很多机器学习的通病。如果模型过拟合,那么得到的模型几乎不能用。为了解决过拟合问题,一般会采用模型集成的方法,即训练多个模型进行组合。此时,训练模型费时就成为一个很大的问题,不仅训练多个模型费时,测试多个模型也是很费时。 Dropout可以比较有效的缓解过拟合的发生,在一定程度上达到正则化的效果

    1.2 什么是Dropout?

    Dropout是Hinton在论文《Improving neural networks by preventing co-adaption of feature detectors》中第一次提出来的,Hinton和其学生的一篇文章更加详细的介绍了Dropout--《Dropout:A Simple Way to Prevent Neural Networks from Overfitting》。下面开始介绍Dropout: Dropout可以作为训练深度神经网络的一种trick供选择。Dropout是指在模型训练时随机的让网络中某些隐层节点的权重不工作,不工作的节点暂时可以认为不是网络结构的一部分。在前向传播的时候,让某个神经元的激活值以一定的概率p停止工作,这样可以使模型泛化性更强,因为它不会太依赖某些局部的特征,如下图所示,在网络训练时,会有一部分节点不起作用或不参与训练。

    被抛弃对节点的影响dropout对于节点的影响表现在,一旦某个节点被选定为抛弃的节点,那么对于神经网络的forward过程这个节点的输出就被置为0;对于backward过程,这个节点的权重和偏置不参与更新。也就是说,在某次迭代中,网络中有部分节点不参与这一次的训练,整个网络结构等效于下图右侧(左侧是dropout前的)。

    图1

    1.3 Dropout工作流程

    假设我们需要训练一个神经网络,如图所示: 图2:标准的神经网络 输入为x输出为y,正常流程为:我们首先把x通过网络前向传播,然后把误差反向传播以决定如何更新参数让网络进行学习。使用Dropout之后,过程变成如下: (1)首先随机(临时)删掉网络中一半的隐藏神经元,输入输出神经元保持不变,如下图所示(图中虚线部分为部分被临时删除的神经元) 图3:部分被删除的神经元

    (2) 然后把输入x通过修改后的网络前向传播,然后把得到的损失结果通过修改的网络反向传播。一小批训练样本执行完这个过程后,在没有被删除的神经元上按照随机梯度下降法更新对应的参数(w,b)。 (3)重复过程(1)、(2):

    • 恢复被删掉的神经元(此时被删除的神经元保持原样,而没有被删除的神经元已经有所更新)

    • 从隐藏层神经元中随机选择一个一半大小的子集临时删除掉(备份被删除神经元的参数)。

    • 对一小批训练样本,先前向传播然后反向传播损失并根据随机梯度下降法更新参数(w,b)(没有被删除的那一部分参数得到更新,删除的神经元参数 保持被删除前的结果)。

    1.4 Dropout在神经网络中的作用

    假设有一个​层隐藏层的神经网络,​用来表示网络隐藏层,其中​表示​层的向量输入,​表示​层的向量输出(其中​表示输入),​和​表示​层的权值和偏置值。 (1)模型训练阶段: 图4

    标准的神经网络的前向传播操作可以描述为:

    图5

    其中,​代表激活函数。

    而使用dropout的神经网络,前向传播操作为:

    图6

    对于每一层,​是一个独立的伯努利随机变量向量,随机生成概率满足P的0、1向量。

    代码层面实现让某个神经元以概率p停止工作,其实就是让它的激活函数值依照概率p变为0。比如我们某一层网络神经元的个数为1000个,其激活函数输出值为y1、y2、y3、......、y1000,我们dropout比率选择0.4,那么这一层神经元经过dropout后,1000个神经元中会有大约400个的值被置为0。

    该向量​与每一层的输出进行点乘操作,从而得到"瘦小的输出"(thinned output)。"瘦小的输出"(thinned output)被用作下一层的输入,这个过程用于每一层。该方法所得到的网络等价于从一个大的网络中进行采样得到的子网络。接着,损失函数的梯度通过反向传播返回到子网络中。

    图7

    (2) 模型测试阶段

    在测试阶段,不使用dropout,权值缩放为:

    图8

    1.4 为什么Dropout可以解决过拟合?

    (1)取平均的作用:先回到标准的模型即没有dropout,我们用相同的训练数据去训练5个不同的神经网络,一般会得到5个不同的结果,此时我们可以采用 “5个结果取均值”或者“多数取胜的投票策略”去决定最终结果。例如3个网络判断结果为数字9,那么很有可能真正的结果就是数字9,其它两个网络给出了错误结果。这种“综合起来取平均”的策略通常可以有效防止过拟合问题。因为不同的网络可能产生不同的过拟合,取平均则有可能让一些“相反的”拟合互相抵消。dropout掉不同的隐藏神经元就类似在训练不同的网络,随机删掉一半隐藏神经元导致网络结构已经不同,整个dropout过程就相当于对很多个不同的神经网络取平均。而不同的网络产生不同的过拟合,一些互为“反向”的拟合相互抵消就可以达到整体上减少过拟合。

    (2)减少神经元之间复杂的共适应关系: 因为dropout程序导致两个神经元不一定每次都在一个dropout网络中出现。这样权值的更新不再依赖于有固定关系的隐含节点的共同作用,阻止了某些特征仅仅在其它特定特征下才有效果的情况 。迫使网络去学习更加鲁棒的特征 ,这些特征在其它的神经元的随机子集中也存在。换句话说假如我们的神经网络是在做出某种预测,它不应该对一些特定的线索片段太过敏感,即使丢失特定的线索,它也应该可以从众多其它线索中学习一些共同的特征。从这个角度看dropout就有点像L1,L2正则,减少权重使得网络对丢失特定神经元连接的鲁棒性提高。

    1.5 源码分析

    Keras开源项目中Dropout函数代码实现所在的文件地址:

    https://github.com/fchollet/keras/blob/master/keras/backend/theano_backend.py

    Dropout实现函数如下:

    图9

    通过对Keras中Dropout实现函数做一些修改,让dropout函数可以单独运行。

    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
    
     # 我们通过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)
    
     x *= random_tensor
     print(x)
     x /= retain_prob
    
     return x
    
    #对dropout的测试,大家可以跑一下上面的函数,了解一个输入x向量,经过dropout的结果 
    x=np.asarray([1,2,3,4,5,6,7,8,9,10],dtype=np.float32)
    dropout(x,0.4)
    

    注意: Keras中Dropout的实现,是屏蔽掉某些神经元,使其激活值为0以后,对激活值向量x1……x1000进行放大,也就是乘以1/(1-p)。

    思考:上面我们介绍了两种方法进行Dropout的缩放,那么Dropout为什么需要进行缩放呢?

    因为我们训练的时候会随机的丢弃一些神经元,但是预测的时候就没办法随机丢弃了。如果丢弃一些神经元,这会带来结果不稳定的问题,也就是给定一个测试数据,有时候输出a有时候输出b,结果不稳定,这是实际系统不能接受的,用户可能认为模型预测不准。那么一种”补偿“的方案就是每个神经元的权重都乘以一个p,这样在“总体上”使得测试数据和训练数据是大致一样的。比如一个神经元的输出是x,那么在训练的时候它有p的概率参与训练,(1-p)的概率丢弃,那么它输出的期望是px+(1-p)0=px。因此测试的时候把这个神经元的权重乘以p可以得到同样的期望。

    总结:

    当前Dropout被大量利用于全连接网络,而且一般认为设置为0.5或者0.3,而在卷积网络隐藏层中由于卷积自身的稀疏化以及稀疏化的ReLu函数的大量使用等原因,Dropout策略在卷积网络隐藏层中使用较少。总体而言,Dropout是一个超参,需要根据具体的网络、具体的应用领域进行尝试。

    什么时候使用Dropout?

    Dropout 作为一种随机正则化策略,理论上可以用于任何地方;但是在Hinton的论文中,dropout被使用在全连接层(full-connected layer)中,这是由于全连接层包含大量的参数,可能会存在参数共适应(co-adaption)问题,因此应用于全连接层能够起到较好的作用,而且dropout的参数一般设置为0.5。

    同样,Dropout也可以用于卷积层(convolutional layer)中,但此时dropout的参数一般设置为p=0.1 或 0.2(即只丢弃0.1 或 0.2的参数)。Dropout 在卷积层使用一般是在卷积层的激活函数之后:CONV-->RELU-->Dropout。

    2. Dropout-- 一种正则化方法

    2.1 机器学习中的过拟合问题

    在相对较小的数据集上训练比较大的神经网络模型时,很容易出现过拟合的现象。原因:这是由于模型强大的学习能力,针对训练数据中的噪声数据,也进行了学习(即模型不仅学习了训练数据的特征feature,同时也学习了噪声的特征feature),因此当模型在新的数据上进行测试时,将会导致很差的效果--这是由于过拟合问题导致的模型泛化能力下降(模型泛化能力是指:当前模型不仅能够很好的学习训练数据,而且对未出现过的数据(该数据同样来源于模型的同一分布)也能具有很好的预测能力)

    针对过拟合问题的一种方法是:减轻过拟合的一种方法是找到拟合该训练数据的所有可能的不同的网络模型,通过对所有模型预测结果进行平均。但是该种方法不现实,但是我们可以通过使用一些小的不同的模型来近似实现该种效果,我们称之为Ensemble Learning(集成学习)[1]。同样,集成学习需要多个网络都进行训练和存储,对于模型较大的话,将需要很长时间来训练和调试(tune)。

    2. 2 随机丢弃节点(Random Drop Nodes)

    Dropout作为一种正则化方法,近似于同时训练了大量不同网络结构的模型。在训练时,某些层(输入层和隐藏层)的一些节点以一定的概率被丢弃不用, dropout对于节点的影响表现在,一旦某个节点被选定为抛弃的节点,那么对于神经网络的forward过程这个节点的输出就被置为0;对于backward过程,这个节点的权重和偏置不参与更新。也就是说,在某次迭代中,网络中有部分节点不参与这一次的训练。

    优点:可以说,Dropout使得训练过程更加繁忙,参与训练的同一层节点要承担起其他被dropout节点的责任,来学习前一层的输入。这种思想打破了网络中节点之间的共适应关系,使得模型更加鲁棒。

    缺点:作为dropout的负面影响,即使在没有稀疏性诱导的正则化函数情况下,隐藏层神经元的激活也变得稀疏。因此,使用dropout会自动导致sparse representation(稀疏表达)

    由于dropout是随机采样进行的,因此在训练的时候会降低网络的体积(capacity),在使用dropout时,要求网络更宽或者说具有更多的节点。

    2.3 如何使用Dropout?

    首先,Dropout可以使用在神经网络的每一层中,如卷积层,稠密全连接层,循环层(recurrent layer),长短时记忆网络层(Long short-term network)。其中keep-probability作为一种超参数(hyperparameter)用来表示输出节点被保留的概率;或者说drop-probability用来表示输出节点被丢弃的概率;这个说法在不同的代码中可能会不太一样。常用的超参数取值为0.5来保存数据节点的个数。针对输入层的话,该值会更大,取0.8或者更大。

    其次,Dropout在测试网络时并不会使用,同时,在测试时要对网络进行缩放,因为在训练时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
    
        # 我们通过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)
    
        x *= random_tensor
    
        print(x)
    
        x /= retain_prob
    
        return x
    
    #对dropout的测试,大家可以跑一下上面的函数,了解一个输入x向量,经过dropout的结果
    
    x=np.asarray([1,2,3,4,5,6,7,8,9,10],dtype=np.float32)
    
    dropout(x,0.4)
    

    使用:dropout在实际中表现效果很好,主要是可以替代权值正则化--weight Normalization的功能(如weight decay),同时dropout结合其他形式的正则化方法能够获得进一步的提升。

    2.4 使用Dropout的小技巧

    1)Dropout可以用在所有类型的网络结构中。如在LSTM当中,针对输入和循环连接(recurrent connection)使用不同的dropout rate可能效果会更好。

    2)Dropout Rate:在隐藏层中,一般为0.5-0.8。

    3)使用更大的网络结构:Dropout在大的网络模型上能够更好的发挥作用,且过拟合的风险较小。如果一个网络只有100个节点,且dropout rate为0.5,那么设计一个网络具有200个节点,则能很好的避免过拟合。

    4)网格搜索参数:将所有可能的dropout rate系统的测试一遍,就能找到一个合适的参数,而不仅仅靠猜测。

    5)权重抑制(weight constraint):由于Dropout引起的一定概率的激活层移除,将会导致网络权值的增加。但是较大的权重将会导致网络不稳定,为了抵消这种影响,可以施加权重约束迫使一层中所有权重的范数(大小)低于指定值。例如,建议最大范数约束值在3-4之间。--这个可能成为微调模型的另一个超参数。

    6)使用更小的数据集。

    6)Dropout的缺点:网络训练达到收敛的时间较长

    参考:

    1、Dropout原理,代码浅析

    2、李理:卷积神经网络之Dropout

    3、Where should I place dropout layers in a neural network?

    4、Where dropout should be inserted?

    5、Analysis on the Dropout Effect in Convolutional Neural Networks

    6、 A Gentle Introduction to Dropout for Regularizing Deep Neural Networks

    7、[1]集成学习(Ensemble learning):集成学习是通过将多个网络模型进行结合,要求每个模型具有一定的准确性,并且要有"多样性",即模型间要具有差异(每个模型要能学到不同的特征)。结合的策略有:1、“投票法”(voting):“少数服从多数”。(详细内容参见周志华《机器学习》第8章 集成学习)

    相关文章

      网友评论

          本文标题:Dropout

          本文链接:https://www.haomeiwen.com/subject/cdycahtx.html