使用列表选择器就地添加

时间:2019-07-10 10:13:33

标签: python pytorch in-place

根据索引是列表还是整数,我正面临着pythorch的某种不一致的行为。看一下这段代码:

pytorch

在第二个示例中,我不明白为什么t无法更新aaa , aab , aac

2 个答案:

答案 0 :(得分:2)

查看两个索引之间的区别:

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

当直接为(0, 0)的第t个元素建立索引时,您将对该条目进行引用,并且可以在其中插入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])

也许您想研究index_add_()来完成任务。

更新 当您使用列表索引分配给t时,您并不是在创建副本(没有意义。

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

翻译为

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

也就是说,在右侧,我们有(0,0)的{​​{1}}子张量的副本,并且我们在该子张量上加了10,其形状为t的形状[1]张量。在左侧,我们将此[10]分配给[10]的{​​{1}}子张量(而不是它的副本-没有意义)。
因此(0,0)的输出是

t

答案 1 :(得分:2)

那是因为花式索引(即使用列表进行索引)返回一个副本,而直接索引则将视图返回到原始张量。一种简单的检查方法是比较基础的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]是如何单个元素,但是由于它只是原始张量的视图,因此它的存储仍然是完整数组。