【问题标题】:Confused on using dropout in batch gradient descent with Q-learning对使用 Q-learning 在批量梯度下降中使用 dropout 感到困惑
【发布时间】:2021-04-02 23:14:11
【问题描述】:

我正在使用 PyTorch 并向我的内层添加 dropout 层。

class MLP(nn.Module):
  #def __init__(self, n_inputs, n_action, n_hidden_layers=2, hidden_dim=8, drop=0.25):
  def __init__(self, console_file, n_inputs, n_action, layers_list, drop=0.25):
    super(MLP, self).__init__()
    print("Layers structure:")
    console_file.write("Layers structure:\n")
    print(f"inputs: {n_inputs}")
    console_file.write(f"inputs: {n_inputs}\n")
    self.layers = []
    for i, layer_size in enumerate(layers_list):
      if i == 0:
        layer = nn.Linear(n_inputs, layer_size)
      else:
        layer = nn.Linear(layers_list[i-1], layer_size)
      self.layers.append(layer)
      print(f"layer {i}: {layer_size}")
      console_file.write(f"layer {i}: {layer_size}\n")
      self.layers.append(nn.LeakyReLU(0.1))
      if drop > 0.01:
        #self.layers.append(nn.Dropout(p = drop**(len(layers_list)-i)))
        self.layers.append(nn.Dropout(p = drop))
        #print(f"drop {i}: {drop**(len(layers_list)-i)}")
        print(f"drop {i}: {drop}")
        #console_file.write(f"drop {i}: {drop**(len(layers_list)-i)}\n")
        console_file.write(f"drop {i}: {drop}\n")
    # final layer
    self.layers.append(nn.Linear(layers_list[-1], n_action))
    self.layers = nn.Sequential(*self.layers)
    print(f"outputs: {n_action}")
    console_file.write(f"outputs: {n_action}\n")
    print("========= NN structure =========\n")
    console_file.write("========= NN structure =========\n\n")
  def forward(self, X):
    return self.layers(X)

  def save_weights(self, path):
    torch.save(self.state_dict(), path)

  def load_weights(self, path):
    self.load_state_dict(torch.load(path))

我确保在训练期间开启训练并在训练之外开启评估模式(移除 droput 层)。

    self.model = he.MLP(console_file, state_size, self.action_size, DIMENSION, DROPOUT)
    if DROPOUT > 0.01:
      self.model.train()
...
      if DROPOUT > 0.01: # before testing
        agent.model.eval()
...
    if DROPOUT > 0.01: # after testing
      self.model.train()

我的困惑是,如果 PyTorch 完全跟踪它在前向传播和稍后选择随机一批输出和奖励的时间之间禁用哪些神经元,并对源自于禁用特定神经元的前向传播。

def train_one_step(model, criterion, optimizer, inputs, targets):  
  # convert to tensors
  inputs = torch.from_numpy(inputs.astype(np.float32))
  targets = torch.from_numpy(targets.astype(np.float32))

  # zero the parameter gradients
  optimizer.zero_grad()

  # Forward pass
  outputs = model(inputs)
  loss = criterion(outputs, targets)

  # Backward and optimize
  loss.backward()
  optimizer.step()

输入和目标来自随机选择(缓冲历史的批次)

对我来说,在前向和反向传播之间禁用 SAME 神经元是有意义的,但由于我在这个主题上找不到任何东西,所以一切都表明 dropout 将随机应用,因此对我来说毫无意义。 要么前向和反向传播需要相同地发生(并且 PyTorch 设法通过一些标记记住,因为我似乎在批处理期间没有传递任何标记)或者我需要了解为什么它们可以随机不同。

【问题讨论】:

  • 随机批次的产出和奖励被选中是什么意思?

标签: python machine-learning pytorch


【解决方案1】:

我不确定是什么问题,但让我试着解释一下事情是如何运作的。

.train() 和 .eval() 仅调用 change the .training flag 到 True 或 False。

Dropout 层在前向传播期间对噪声进行采样。这是转发implementation 的示例(我删除了用于 alpha 的 ifs 和功能丢失以提高可读性):

template<bool feature_dropout, bool alpha_dropout, bool inplace, typename T>
Ctype<inplace> _dropout_impl(T& input, double p, bool train) {
  TORCH_CHECK(p >= 0 && p <= 1, "dropout probability has to be between 0 and 1, but got ", p);
  if (p == 0 || !train || input.numel() == 0) {
    return input;
  }

  if (p == 1) {
    return multiply<inplace>(input, at::zeros({}, input.options()));
  }

  auto noise = at::empty_like(input, LEGACY_CONTIGUOUS_MEMORY_FORMAT);
  noise.bernoulli_(1 - p);
  noise.div_(1 - p);
  return multiply<inplace>(input, noise);
}

如您所见,如果!train(即.eval()),它将按原样返回input。此外,您可以说它“记住”哪些神经元被禁用,就像它“记住”每个活动神经元的值是什么一样。请注意,dropout 层实际上在前一层的输出上用作 0 和(缩放的)1 的掩码。它实际上并没有掩盖神经元,尽管在实践中效果是等效的,因为生成输出乘以 0 的神经元将没有梯度,其余的将得到适当缩放的梯度(因为 .div_(1-p))。

【讨论】:

  • 在执行反向传播之前会处理数以千计的正向传递,基于批量选择(输入、目标)会发生以下情况,其中在根据特定输入计算特定输出、奖励之前使用了 dropout 层 # Forward pass output = model(inputs) loss = criteria(outputs, targets) # 向后优化 loss.backward() optimizer.step()
  • 所以我看不出它如何记住每种情况下使用的 dropout,特别是因为它计算了一个新模型(输入),其中目标包含先前计算的奖励;我想在这种情况下不可能正确使用 dropout
  • @Dan 也许你粘贴了错误的 sn-p... 你的意思是“在执行反向传播之前处理了数千个正向传递”?在您的代码中,前向 (model(inputs)) 紧随其后的是后向 (.backward()) 和梯度更新 (.step())。
  • targets被提前计算和batch,model(inputs)被重新计算为batch;在我看来,正在训练的系统与旧版本之间总是存在差异,但更重要的是,我认为没有理由相信会发生同样的辍学;请注意,根据批次的大小,输入、目标和输出都是多重的
  • @Dan,你能用一些代码或伪代码更新问题吗?目前的sn-ps没有给我们关于这个过程的线索,所以很难理解实际的问题
猜你喜欢
  • 2018-07-15
  • 2017-05-10
  • 2020-06-03
  • 2021-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-08
相关资源
最近更新 更多