Dropout是什么?有什么用?
在我另外一篇解读AlexNet网络的博文中,我提到了Dropout被Alex用来防止模型过拟合:
Dropout就是把隐藏层中神经元的输出设置为0,每个神经元被Dropout概率为r(这是个超参数,在这个网络中r=0.5),这些被‘dropout’掉的神经元不会参与前向计算和后向传播。每次输入一次,这个神经网络就采取的是不一样的神经结构(因为每个神经元被dropout的概率是一样的),但是这些结构都是权值共享的。这样就相当于训练了多个不同的网络模型,提高了泛化能力。
在一些机器学习比赛中,为了解决过拟合问题往往会用到模型融合:比如我们在同一个深度神经网络模型上训练五个不同的模型,然后对不同的模型所得到的结果做融合,从而得到最后的结果。因为不同的模型网络中所得到权重不同,并且神经元的功能也会不一样,模型融合可以提高泛化能力,抑制过拟合现象。
Dropout因此受到启发,并且在学习过程中,丢弃哪些神经元是随机决定,因此模型不会过度依赖某些神经元,能一定程度上抑制过拟合。
测试?训练?
和Batch Normalization一样,Dropout在训练和预测会有所不同。训练时,Dropout会随机丢弃一部分神经元,使其输出为0,那么输出数据的总大小就变小了。例如在计算L2范式的时候,不适用Dropout比适用了Dropout的输出会大。这样在测试的时候就会出现问题,由于测试的时候,Dropout不是起作用的,这将导致训练和预测时的数据分布不一样,为了解决这个问题,有两种方法:
- 训练时以
比例r
随机丢弃一部分神经元,不向后传递它们的信号;预测时向后传递所有神经元的信号,但是将每个神经元上的数值乘以(1−r)
。 - 训练时以
比例r
随机丢弃一部分神经元,不向后传递它们的信号,但是将那些被保留的神经元上的数值除以 (1−r)
;预测时向后传递所有神经元的信号,不做任何处理。
PyTorch测试
# 定义一个只有Dropout层的网络
class Test(nn.Module):
def __init__(self):
super(Test, self).__init__()
# 每个神经元被Dropout的概率为0.5
self.m = nn.Dropout(0.8)
def forward(self, x):
out = self.m(x)
return out
x = torch.rand([2, 2])
print(x)
model = Test()
# 训练时
model.train()
out = model(x)
print(out)
# 测试时
model.eval()
out2 = model(x)
print(out2)
- 结果以及分析
可以看到Pytorch中的Dropout是参照了方法二,训练时以比例r
随机丢弃一部分神经元,不向后传递它们的信号,但是将那些被保留的神经元上的数值除以 (1−r)
;预测时向后传递所有神经元的信号,不做任何处理。