【问题标题】:What is the logic behind this assignment: understanding in-place assignment operations in numpy这个赋值背后的逻辑是什么:了解numpy中的就地赋值操作
【发布时间】:2020-02-07 03:23:36
【问题描述】:

我有两个相当简单的代码给出不同的答案。我知道这是由于共享的参考,但我不太清楚第二种情况到底发生了什么

a = np.ones(5)
b = torch.from_numpy(a)
a=np.add(a, 1, out=a)
print(a)
print(b)

[出]:

[2. 2. 2. 2. 2.]

张量([2., 2., 2., 2., 2.], dtype=torch.float64)

a = np.ones(5)
b = torch.from_numpy(a)
a=a+1
print(a)
print(b)

[出]:

[2. 2. 2. 2. 2.]

张量([1., 1., 1., 1., 1.], dtype=torch.float64)

为什么b在第二种情况下不改变?

【问题讨论】:

  • 使用out=a 可确保将新值写入原始a 对象。使用a = a+1,结果是一个新数组,它不再与用于创建ba 对象有任何联系。这是基本的 Python 行为。一些操作就地修改对象,其他操作创建一个新对象。 a=.... 将新对象分配给变量a;它不会修改之前分配给它的对象。
  • @hpaulj 感谢您的出色见解!我已经在我的回答中链接了 Ned Batchelder 的演讲,其中也有一些关于这种行为的视觉说明:)

标签: python-3.x numpy reference pytorch numpy-ndarray


【解决方案1】:

在第一种情况下,ab 共享相同的内存(即ba 的视图,或者换句话说,b 指向(数组)值 其中a 也指向)和out 参数保证a 的相同内存在np.add() 操作完成后更新。而在第二种情况下,a 是一个新副本,而 a = a+1b 仍然指向 a 的旧值。

尝试第二种情况:

a += 1

并观察ab 确实都更新了。

In [7]: a = np.ones(5) 
   ...: b = torch.from_numpy(a) 
   ...: a += 1   

In [8]: a  
Out[8]: array([2., 2., 2., 2., 2.])

In [9]: b 
Out[9]: tensor([2., 2., 2., 2., 2.], dtype=torch.float64)

作为@hpaulj aptly pointed out in his comment,当我们执行a = a+1 时,会创建一个新对象,a 现在将指向这个新的(数组)对象,而不是b 仍指向的旧对象。这就是b的(数组)没有更新的原因。


为了更好地理解这种行为,您可能需要参考 Ned Batchelder 关于 how names are bind to values in Python 的优秀文章

【讨论】:

  • 我不知道torchfrom_numpy 做了什么。 view 是一个特定的 numpy 术语,指的是共享底层数据缓冲区的新数组对象。 torch 可能就是这种情况,或者a 可能是b 的一个属性。在任何情况下,当将新数组分配给 a 时,该链接确实会保留。
  • @hpaulj torch.from_numpy() 只是从 numpy nd-array 读取并将其转换为 Torch 张量。但是,张量和 numpy 数组共享相同的内存。因此,其中一个的变化将反映在另一个中。
  • a+=1实际上等于a.__iadd__(),我猜numpy实现这个方法来替换a,这就是为什么a+=1也会改变b
猜你喜欢
  • 1970-01-01
  • 2010-12-22
  • 2014-03-05
  • 1970-01-01
  • 2011-05-25
  • 1970-01-01
  • 1970-01-01
  • 2021-05-23
  • 1970-01-01
相关资源
最近更新 更多