dropout ( 减少过拟合)

Dropout可以有效缓解模型过拟合的发生,在一定程度上可以达到正则化的效果。因为dropout程序导致两个神经元不一定每次都在一个dropout网络中出现。这样权值的更新不再依赖于有固定关系的隐含节点的共同作用,阻止了某些特征仅仅在其它特定特征下才有效果的情况 。

在前向传播的时候,让某个神经元的激活值以一定的概率p停止工作,这样可以使模型泛化性更强,因为它不会太依赖某些局部的特征。

具体步骤如下:

  1. 随机屏蔽掉模型隐藏层中的某些神经元(不更新),输入层和输出层保持不变;
  2. 输入层接收数据并通过修改的网络执行前向传播,得到损失结果后通过修改的网络进行反向传播。执行完一个batch的数据后,在未修改的网络神经元上按随机梯度下降法更新模型参数;
  3. 反复执行过程 1 2。每次都随机屏蔽掉部分神经元,并在参数更新后进行恢复。被屏蔽的神经元会保持原状,而未被屏蔽的神经元则会被更新。

demo:

# coding:utf-8
import numpy as np
 
# dropout函数的实现
def dropout(x, level):#x是本层网络的激活值。Level就是dropout就是每个神经元要被丢弃的概率。
    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)
'''
[1 1 0 0 0 1 0 1 1 1]
[ 1.  2.  0.  0.  0.  6.  0.  8.  9. 10.]
array([ 1.6666666,  3.3333333,  0.       ,  0.       ,  0.       ,
       10.       ,  0.       , 13.333333 , 14.999999 , 16.666666 ],
      dtype=float32)
'''

注意: 如果是训练时进行调整,就应该是除以保留率,如果是测试时调整则是乘上保留率。目的就是是的神经元的输出x的期望在训练和测试时都是px。

思考:Dropout为什么需要进行缩放呢?

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

总结:

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

你可能感兴趣的:(Python,NLP,python,深度学习)