Inplace добавить со списком селекторов - PullRequest
3 голосов
/ 10 июля 2019

Я сталкиваюсь с каким-то непоследовательным поведением питора в соответствии с тем, является ли индекс списком или целым числом.Посмотрите на этот фрагмент кода:

# 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 во втором примере!

Ответы [ 2 ]

2 голосов
/ 10 июля 2019

Это потому, что причудливая индексация (т. Е. Использование списков для индексации) возвращает копию, а прямая индексация возвращает представление к исходному тензору.Простой способ проверить это состоит в том, чтобы сравнить базовое хранилище

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] представляет собой один элемент, но его хранилище по-прежнему является полным массивом, посколькуэто только вид оригинального тензора.

2 голосов
/ 10 июля 2019

Смотрите разницу между двумя индексами:

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-мерный тензор, форма которого равна [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) t, и мы добавляем 10 к этому субтензору, в результате чего получается форма [1] тензор со значением [10]. С левой стороны мы присваиваем [10] субтензору (0,0) t (не его копии - это не имеет смысла).
Поэтому на выходе t[[0], [0]] += 10 будет

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