如何在Pytorch中实现dropout,以及在哪里应用它。

22

我不太确定这是否正确。很遗憾,我找不到很多关于如何给神经网络加参数的好例子。

你认为在这两个类别中采用这种方式进行退出有效吗?首先,我将写出原始类:

class NeuralNet(nn.Module):
  def __init__(self, input_size, hidden_size, num_classes, p = dropout):
      super(NeuralNet, self).__init__()
      self.fc1 = nn.Linear(input_size, hidden_size)
      self.fc2 = nn.Linear(hidden_size, hidden_size)
      self.fc3 = nn.Linear(hidden_size, num_classes)

  def forward(self, x):
      out = F.relu(self.fc1(x))
      out = F.relu(self.fc2(out))
      out = self.fc3(out)
      return out

然后在这里,我发现有两种不同的写法,但我不知道如何区分。第一种使用:

self.drop_layer = nn.Dropout(p=p) 

反之第二个:

self.dropout = nn.Dropout(p) 

这是我的结果:

class NeuralNet(nn.Module):
  def __init__(self, input_size, hidden_size, num_classes, p = dropout):
      super(NeuralNet, self).__init__()
      self.fc1 = nn.Linear(input_size, hidden_size)
      self.fc2 = nn.Linear(hidden_size, hidden_size)
      self.fc3 = nn.Linear(hidden_size, num_classes)
      self.drop_layer = nn.Dropout(p=p)

  def forward(self, x):
      out = F.relu(self.fc1(x))
      out = F.relu(self.fc2(out))
      out = self.fc3(out)
      return out


 class NeuralNet(nn.Module):
  def __init__(self, input_size, hidden_size, num_classes, p = dropout):
      super(NeuralNet, self).__init__()
      self.fc1 = nn.Linear(input_size, hidden_size)
      self.fc2 = nn.Linear(hidden_size, hidden_size)
      self.fc3 = nn.Linear(hidden_size, num_classes)
      self.dropout = nn.Dropout(p) 

  def forward(self, x):
      out = F.relu(self.fc1(x))
      out = F.relu(self.fc2(out))
      out = self.fc3(out)
      return out

这是否可行?如果不行,如何改进,它是否能给我期望的结果,即创建一个可以丢弃一些神经元的神经网络。重要细节:我只想丢弃神经网络的第二层,其他部分不要动!


1
我很高兴看到那个问题有这么多的浏览量,如果你喜欢我的问题,请点赞!我正在努力赚取积分。 - Marine Galantin
1个回答

20

您提供的两个示例完全相同。self.drop_layer = nn.Dropout(p=p)self.dropout = nn.Dropout(p)之间唯一的区别在于作者将它们分配给了不同的变量名。dropout层通常在.__init__()方法中定义,并在.forward()中调用。像这样:

 class NeuralNet(nn.Module):
  def __init__(self, input_size, hidden_size, num_classes, p = dropout):
      super(NeuralNet, self).__init__()
      self.fc1 = nn.Linear(input_size, hidden_size)
      self.fc2 = nn.Linear(hidden_size, hidden_size)
      self.fc3 = nn.Linear(hidden_size, num_classes)
      self.dropout = nn.Dropout(p) 

  def forward(self, x):
      out = F.relu(self.fc1(x))
      out = F.relu(self.fc2(out))
      out = self.dropout(self.fc3(out))
      return out

你可以进行测试:

import torch
import torch.nn  as nn

m = nn.Dropout(p=0.5)
input = torch.randn(20, 16)
print(torch.sum(torch.nonzero(input)))
print(torch.sum(torch.nonzero(m(input))))

tensor(5440) # sum of nonzero values
tensor(2656) # sum on nonzero values after dropout

让我们来可视化它:

import torch
import torch.nn as nn
input = torch.randn(5, 5)
print(input)

tensor([[ 1.1404,  0.2102, -0.1237,  0.4240,  0.0174],
        [-2.0872,  1.2790,  0.7804, -0.0962, -0.9730],
        [ 0.4788, -1.3408,  0.0483,  2.4125, -1.2463],
        [ 1.5761,  0.3592,  0.2302,  1.3980,  0.0154],
        [-0.4308,  0.2484,  0.8584,  0.1689, -1.3607]])

现在,让我们应用dropout:

m = nn.Dropout(p=0.5)
output = m(input)
print(output)

tensor([[ 0.0000,  0.0000, -0.0000,  0.8481,  0.0000],
        [-0.0000,  0.0000,  1.5608, -0.0000, -1.9459],
        [ 0.0000, -0.0000,  0.0000,  0.0000, -0.0000],
        [ 0.0000,  0.7184,  0.4604,  2.7959,  0.0308],
        [-0.0000,  0.0000,  0.0000,  0.0000, -0.0000]])

由于我们设置了概率p = 0.5,因此大约一半的神经元已被设为零!


我还没有使用F.方法,但nn.会有什么不同吗?所以我应该添加你写的那行代码吗?这会在隐藏层中实现dropout吗? - Marine Galantin
抱歉,这是一样的。我改了它。是的,没错。看看我的编辑。你可以自己进行测试。 - Nicolas Gervais
谢谢你,Nicolas。只是有一点我不太明白:你是如何测试的?我得到的输出是“tensor5440”。这是什么意思?你写了“非零值之和”,我不明白它是什么意思。此外,我的输出是5440和2450。 - Marine Galantin
一个dropout层将一定数量的神经元设置为零。我们传递的参数 p=0.5 是任何神经元被设置为零的概率。因此,每次运行代码时,非零值的总和应该大约减少一半。想象一个大小为5x5的填充有1的2D矩阵。非零值的总和将是 5*5=25。在dropout之后,大约一半的1会变成0。因此,非零值的总和将大约为12。 - Nicolas Gervais

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接