【问题标题】:What does the underscore suffix in PyTorch functions mean?PyTorch 函数中的下划线后缀是什么意思?
【发布时间】:2019-03-25 23:35:08
【问题描述】:

在 PyTorch 中,张量的许多方法存在于两个版本中 - 一个带有下划线后缀,一个没有。如果我尝试一下,它们似乎会做同样的事情:

In [1]: import torch

In [2]: a = torch.tensor([2, 4, 6])

In [3]: a.add(10)
Out[3]: tensor([12, 14, 16])

In [4]: a.add_(10)
Out[4]: tensor([12, 14, 16])

有什么区别

  • torch.addtorch.add_
  • torch.subtorch.sub_
  • ...等等?

【问题讨论】:

    标签: python pytorch


    【解决方案1】:

    根据documentation,以下划线结尾的方法就地改变张量。这意味着没有通过执行操作分配新内存,一般 increase performance,但can lead to problems and worse performance in PyTorch

    In [2]: a = torch.tensor([2, 4, 6])
    

    tensor.add()

    In [3]: b = a.add(10)
    
    In [4]: a is b
    Out[4]: False # b is a new tensor, new memory was allocated
    

    tensor.add_()

    In [3]: b = a.add_(10)
    
    In [4]: a is b
    Out[4]: True # Same object, no new memory was allocated
    

    请注意,运算符++= 也是two different implementations+ 使用.add() 创建一个新的张量,而+= 使用.add_() 修改张量

    In [2]: a = torch.tensor([2, 4, 6])
    
    In [3]: id(a)
    Out[3]: 140250660654104
    
    In [4]: a += 10
    
    In [5]: id(a)
    Out[5]: 140250660654104 # Still the same object, no memory allocation was required
    
    In [6]: a = a + 10
    
    In [7]: id(a)
    Out[7]: 140250649668272 # New object was created
    

    【讨论】:

    • 你是否有任何 PyTorch 源代码:"就地 [...] 操作 [...] 可以显着提高性能 [...] 你因此应该更喜欢就地方法” ?据我所知,PyTorch 的情况恰恰相反——在大多数情况下,强烈建议不要在 PyTorch 中使用 in-place 操作。 pytorch.org/docs/stable/notes/…
    【解决方案2】:

    您已经回答了自己的问题,即下划线表示 PyTorch 中的就地操作。但是我想简要指出为什么就地操作可能会出现问题:

    • 首先,在 PyTorch 网站上,建议在大多数情况下不要使用就地操作。除非在沉重的内存压力下工作,否则在大多数情况下更有效不使用就地操作
      https://pytorch.org/docs/stable/notes/autograd.html#in-place-operations-with-autograd

    • 其次,在使用就地操作时计算梯度可能会出现问题:

      每个张量都有一个版本计数器,每次递增 它在任何操作中都被标记为脏。当一个函数保存任何张量时 对于向后,它们包含张量的版本计数器保存为 好吧。一旦您访问self.saved_tensors,它就会被检查,如果是 大于保存的值会引发错误。这确保了如果 您正在使用就地功能并且没有看到任何错误,您可以 确保计算出的梯度是正确的。 Same source as above.

    这是从您发布的答案中截取的经过稍微修改的示例:

    首先是就地版本:

    import torch
    a = torch.tensor([2, 4, 6], requires_grad=True, dtype=torch.float)
    adding_tensor = torch.rand(3)
    b = a.add_(adding_tensor)
    c = torch.sum(b)
    c.backward()
    print(c.grad_fn)
    

    导致此错误的原因:

    ---------------------------------------------------------------------------
    RuntimeError                              Traceback (most recent call last)
    <ipython-input-27-c38b252ffe5f> in <module>
          2 a = torch.tensor([2, 4, 6], requires_grad=True, dtype=torch.float)
          3 adding_tensor = torch.rand(3)
    ----> 4 b = a.add_(adding_tensor)
          5 c = torch.sum(b)
          6 c.backward()
    
    RuntimeError: a leaf Variable that requires grad has been used in an in-place operation.
    

    其次是非就地版本:

    import torch
    a = torch.tensor([2, 4, 6], requires_grad=True, dtype=torch.float)
    adding_tensor = torch.rand(3)
    b = a.add(adding_tensor)
    c = torch.sum(b)
    c.backward()
    print(c.grad_fn)
    

    效果很好 - 输出:

    <SumBackward0 object at 0x7f06b27a1da0>
    

    因此,作为外卖,我只想指出在 PyTorch 中谨慎使用就地操作。

    【讨论】:

      猜你喜欢
      • 2022-12-07
      • 1970-01-01
      • 1970-01-01
      • 2011-09-03
      • 2013-01-25
      • 2012-12-07
      • 1970-01-01
      • 2017-09-25
      • 2015-02-08
      相关资源
      最近更新 更多