Python 使用列表选择器就地添加
我正面临pythorch某种程度上不一致的行为,根据weither的说法,索引是一个列表或整数。请看这段代码:Python 使用列表选择器就地添加,python,pytorch,in-place,Python,Pytorch,In Place,我正面临pythorch某种程度上不一致的行为,根据weither的说法,索引是一个列表或整数。请看这段代码: # First example, integer selector ==> Ok t = torch.tensor([[0, 1], [1, 0]]) t[0, 0].add_(10) print(t) tensor([[10, 1], [ 1, 0]]) # Second example, list selector ==> ??? t = torc
# First example, integer selector ==> Ok
t = torch.tensor([[0, 1], [1, 0]])
t[0, 0].add_(10)
print(t)
tensor([[10, 1],
[ 1, 0]])
# Second example, list selector ==> ???
t = torch.tensor([[0, 1], [1, 0]])
t[[0], [0]].add_(10) # notice the list selector
print(t)
tensor([[0, 1],
[1, 0]])
#Third example, list selector with inplace add operator ==> Ok
t = torch.tensor([[0, 1], [1, 0]])
t[[0], [0]] += 10
print(t)
tensor([[10, 1],
[ 1, 0]])
我不明白为什么在第二个示例中,
pytorch
无法更新t
查看两个索引之间的差异:
In []: t[0, 0].shape
当您直接为t
的(0,0)
第个元素编制索引时,您有一个对该条目的引用,您可以将添加到该条目中。t[0,0]
的形状是[]
-也就是说,您得到了一个标量返回-(0,0)
条目的内容。
但是,当您使用列表索引([0],[0])
时,返回的是一维张量,形状是[1]
。也就是说,你得到了一个t
的次张量的副本。然后在中添加子张量的副本,对原始t
没有影响:
[]中的:r=t[[0],[0]]。添加(10)
In[]:t
出[]:
张量([[0,1],
[1, 0]])
In[]:r
Out[]:张量([10])
也许你想调查一下以完成你的任务
更新
当您使用列表索引分配给t
时,您并没有创建副本(这毫无意义。因此
t[[0],[0]+=10
转化为
t[[0],[0]]=t[[0],[0]]+10
也就是说,在右边我们有一个(0,0)
次张量t
的副本,我们在这个次张量上加上10,得到一个形状[1]
的值[10]
的张量。在左边我们把这个[10]
分配给(0,0)
次张量t
(不要复制它-这毫无意义)。
因此,t[[0],[0]+=10的输出为
张量([[10,1],
[ 1, 0]])
这是因为奇特的索引(即使用列表索引)返回一个副本,而直接索引返回一个原始张量的视图。检查这种情况的一个简单方法是比较底层张量
注意a[0]
是一个单独的元素,但它的存储仍然是完整的数组,因为它只是原始张量的一个视图。为了澄清,我想这里返回的张量的形状是不相关的,零维张量也可以是视图或副本。重点是列表索引返回一个副本,并且在问题中对该副本调用了add
。如果不是因为第三个例子(见编辑的问题),我可以接受你的答案。如果t[[0],[0]]只是t
的一个副本,那怎么可能呢?谢谢你的回答@ShaiI可以接受你的答案,如果不是因为第三个例子(见编辑的问题)。如果t[[0],[0]],那怎么可能呢
只是t的副本吗?
Out[]: torch.Size([])
In []: t[[0], [0]].shape
Out[]: torch.Size([1])
In [16]: a = torch.arange(3)
In [17]: a.storage()
Out[17]:
0
1
2
[torch.LongStorage of size 3]
In [18]: a[0].storage()
Out[18]:
0
1
2
[torch.LongStorage of size 3]
In [19]: a[[0]].storage()
Out[19]:
0
[torch.LongStorage of size 1]