Dropout字面意思就是“丢掉”,是为了防止神经网络出现过拟合,让隐藏层的节点在每次迭代时(包括正向和反向传播)有一定几率(keep-prob)失效。以提高模型的泛化能力,减少过拟合。
Dropout属于一种正则化技术。Dropout的probability,实践中最常用的是0.5(或0.1,0.05)
Dropout不能用于测试集,只能用于训练集!!!
即
就比如
这样可以认出来
这样依然可以
一般情况,dropout rate 设为0.3-0.5即可
训练和测试时的dropout
注意,dropout只在训练时采用,是为了减少神经元对部分上层神经元的依赖,类似将多个不同网络结构的模型集成起来,减少过拟合的风险。
dropout一般放在fc层后防止过拟合,提高模型泛化能力,由于卷积层参数较少,很少有放在卷积层后面的情况
而在测试时,应该用整个训练好的模型,因此不需要dropout。用model.eval()即可关闭dropout.
当使用Dropout时,通常训练所需的时间会变长。但是当模型收敛后,他将会有更好的泛化能力
Dropout 如何平衡训练和测试时的差异呢?(dropout训练时的rescale)
Dropout ,在训练时以一定的概率使神经元失活,实际上就是让对应神经元的输出为0
假设失活概率为 p ,就是这一层中的每个神经元都有p的概率失活,如下图的三层网络结构中,如果失活概率为0.5,则平均每一次训练有3个神经元失活,所以输出层每个神经元只有3个输入,而实际测试时是不会有dropout的,输出层每个神经元都有6个输入,这样在训练和测试时,输出层每个神经元的输入和的期望会有量级上的差异。
因此在训练时还要对第二层的输出数据除以(1-p)之后再传给输出层神经元,使其扩大,作为神经元失活的补偿,以使得在训练时和测试时每一层输入有大致相同的期望。
即这一层有一部分数据置零了,没置零的哪些相应扩大,使得后面的层在算wx+b的时候,求和得到的值还是相同量级的
为什么神经网络中的dropout可以作为正则化
关于dropout的工作原理有几种解释。我们可以将其视为模型平均的一种形式:我们可以在每一步中“去掉”模型的一部分并取平均值。另外,它还会增加噪音,自然会产生调节的效果。最后,它还可以稀释权重,从根本上阻止神经网络中神经元的共适应。
为什么Dropout可以看作是一种集成学习
因为对于采用了dropout的网络,一个mini-batch中的每个样本所走的网络结构是不同的,于是可以理解为我们在同时训练多个网络,所以可以视作集成学习。
Dropout的使用
nn.Dropout()
import torch from torch import nn my_dropout = nn.Dropout(p=0.2) input = torch.randn(20, 16) output = my_dropout(input)
可以看到,output中有些值已经被随机置0了
而没有置零的也是除以了0.8,0.1949/0.8=0.2437
Dropout的位置
Dropout一般放在全连接层防止过拟合,提高模型返回能力,由于卷积层参数较少,很少有放在卷积层后面的情况,卷积层一般使用batch norm。
dropout 应当置于 activation layer 之后
CONV/FC -> BatchNorm -> ReLu(or other activation) -> Dropout -> CONV/FC
手动实现
用numpy写的
import torch from torch import nn import numpy as np #模拟两层网络 def train(p, x, w1, b1, w2, b2): layer1 = np.maximum(0, np.dot(w1, x) + b1) mask1 = np.random.binomial(1, 1-p, layer1.shape) layer1 = layer1 * mask1 layer1 = layer1 / (1-p) layer2 = np.maximum(0, np.dot(w2, layer1) + b2) mask2 = np.random.binomial(1, 1-p, layer2.shape) layer2 = layer2 * mask2 layer2 = layer2 / (1-p) return layer2 def test(x, w1, b1, w2, b2): layer1 = np.maximum(0, np.dot(w1, x)+b1) layer2 = np.maximum(0, np.dot(w2, layer1) + b2) return layer2 input = np.random.randn(5, 4) w1 = np.random.rand(30,20) b1 = np.random.rand(30) w2 = np.random.rand(40,30) b2 = np.random.rand(40) output1 = train(p=0.5, x=input.reshape(-1), w1=w1, b1=b1, w2=w2, b2=b2) print(output1) output2 = test(x=input.reshape(-1), w1=w1, b1=b1, w2=w2, b2=b2) print(output2)