一、Dropout层的作用
??dropout 能够避免过拟合,我们往往会在全连接层这类参数比较多的层中使用dropout;在训练包含dropout层的神经网络中,每个批次的训练数据都是随机选择,实质是训练了多个子神经网络,因为在不同的子网络中随机忽略的权重的位置不同,最后在测试的过程中,将这些小的子网络组合起来,类似一种投票的机制来作预测,有点类似于集成学习的感觉。
??关于dropout,有nn.Dropout和nn.functional.dropout两种。推荐使用nn.xxx,因为一般情况下只有训练train时才用dropout,在eval不需要dropout。使用nn.Dropout,在调用model.eval()后,模型的dropout层和批归一化(batchnorm) 都关闭,但用nn.functional.dropout,在没有设置training模式下调用model.eval()后不会关闭dropout。 ??这里关闭dropout等的目的是为了测试我们训练好的网络。在eval模式下,dropout层会让所有的激活单元都通过,而batchnorm层会停止计算和更新mean和var,直接使用在train训练阶段已经学出的mean和var值。同时我们在用模型做预测的时候也应该声明model.eval()。
注??:为了进一步加速模型的测试,我们可以设置with torch.no_grad() ,主要是用于停止autograd模块的工作,以起到加速和节省显存的作用,具体行为就是停止梯度gradient计算和储存,从而节省了GPU算力和显存,但是并不会影响dropout和batchnorm层的行为,这样我们可以使用更大的batch进行测试。
model.eval()下不启用 Batch Normalization 和 Dropout。 如果模型中有BN层(Batch Normalization)和Dropout,在测试时添加model.eval()。model.eval()是保证BN层能够用全部训练数据的均值和方差,即测试过程中要保证BN层的均值和方差不变。对于Dropout,model.eval()是利用到了所有网络连接,即不进行随机舍弃神经元。
二、Dropout层的使用方法
??以下是nn.Dropout和nn.functional.dropout两种具体的使用方法:
class Dropout1(nn.Module):
def __init__(self):
super(Dropout1, self).__init__()
self.fc = nn.Linear(100,20)
def forward(self, input):
out = self.fc(input)
out = F.dropout(out, p=0.5, training=self.training)
return out
Net = Dropout1()
Net.train()
class Dropout2(nn.Module):
def __init__(self):
super(Dropout2, self).__init__()
self.fc = nn.Linear(100,20)
self.dropout = nn.Dropout(p=0.5)
def forward(self, input):
out = self.fc(input)
out = self.dropout(out)
return out
Net = Dropout2()
Net.train()
三、RNN中使用Dropout(进阶)
??偶然间我在一个项目中发现其在LSTM上下层连接的时候使用了dropout来控制模型的过拟合;通过我查阅了一些资料发现dropour只能用于特定的rnn连接上,在gru上边会出现错误,其具体的原因来自于模型的具体结构问题,具体详情可以参考:https://www.jianshu.com/p/be34e53d54e6
class RNNDropout(nn.Dropout):
"""
Dropout layer for the inputs of RNNs.
Apply the same dropout mask to all the elements of the same sequence in
a batch of sequences of size (batch, sequences_length, embedding_dim).
"""
def forward(self, sequences_batch):
"""
Apply dropout to the input batch of sequences.
Args:
sequences_batch: A batch of sequences of vectors that will serve
as input to an RNN.
Tensor of size (batch, sequences_length, emebdding_dim).
Returns:
A new tensor on which dropout has been applied.
"""
ones = sequences_batch.data.new_ones(sequences_batch.shape[0],
sequences_batch.shape[-1])
dropout_mask = nn.functional.dropout(ones, self.p, self.training,
inplace=False)
return dropout_mask.unsqueeze(1) * sequences_batch
以上是我对dropout的一些个人理解,欢迎大家补充或提出见解👏
|