带列表选择器的就地添加

2024-06-16 13:46:06 发布

您现在位置:Python中文网/ 问答频道 /正文

我面临着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 = 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!你知道吗


Tags: 代码add列表exampleok整数integertorch
2条回答

请参见两种索引之间的区别:

In []: t[0, 0].shape
Out[]: torch.Size([])
In []: t[[0], [0]].shape
Out[]: torch.Size([1])

当您直接索引t(0, 0)元素时,您有一个对该条目的引用,您可以将add_放入该条目。t[0,0]的形状是[]——也就是说,你得到了一个标量,即(0,0)项的内容。
但是,当使用列表索引([0], [0])时,得到的是一维张量,形状是[1]。也就是说,得到t的次张量的拷贝。然后你把add_放在亚张量的副本上,你对原始的t没有影响:

In []: r = t[[0], [0]].add_(10)
In []: t
Out[]:
tensor([[0, 1],
        [1, 0]])

In []: r
Out[]: tensor([10])

也许你想研究^{}来完成你的任务。你知道吗

更新 当您使用列表索引分配给t时,您并不是在创建副本(这毫无意义)。所以

t[[0], [0]] += 10

转换为

t[[0], [0]] = t[[0], [0]] + 10

也就是说,在右边,我们有一个(0,0)t子张量的拷贝,我们在这个子张量上加10,得到一个[1]的形状张量,值为[10]。在左边,我们把这个[10]赋给t(0,0)子张量(不是赋给它的一个副本-这毫无意义)。
因此t[[0], [0]] += 10的输出是

tensor([[10,  1],
        [ 1,  0]])

这是因为花哨的索引(即使用列表索引)返回一个副本,而直接索引返回一个原始张量的视图。检查这种情况的一个简单方法是比较底层的storage

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]

注意a[0]是一个元素,但是它的存储仍然是完整的数组,因为它只是原始张量的一个视图。你知道吗

相关问题 更多 >