Я пытаюсь создать 2D-тензор четных срезов из 1D-тензора в PyTorch. Скажем, у нас есть тензор одномерных данных и тензоры индексов как:
>>> data = torch.arange(10)
>>> data
tensor([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> starts = torch.tensor([0, 3, 4, 1])
>>> ends = starts + 2
>>> starts
tensor([0, 3, 4, 1])
>>> ends
tensor([2, 5, 6, 3])
Как я могу проиндексировать тензор data, не зацикливаясь и не разрезая каждый набор индексов, чтобы получить следующий результат:
>>> dataSlices
tensor([[0, 1],
[3, 4],
[4, 5],
[1, 2]])
Моя первая очевидная мысль — просто поставить starts и ends, как если бы вы использовали отдельные индексы, но это просто ошибка:
>>> data[starts:ends]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: only integer tensors of a single element can be converted to an index
Я просмотрел некоторые части документации, но не могу найти способ, я упустил что-то очевидное?
Если бы это был список, zip решил бы вашу проблему
Похоже, вам нужно: torch.transpose().
И используйте решение из этого ответа @bachr: https://stackoverflow.com/a/60367265/3456886
Переход от строки: starts = torch.tensor([0, 3, 4, 1]) И изменение рядом с: ends = starts+ 1, чтобы получить правильный массив. Затем транспонирование позволит вам объединить тензор в желаемый результат dataSlices
Вы можете сделать это с помощью torch.take. Чтобы получить желаемый результат, вам нужно вычесть 1 из ваших конечных индексов, так как он принимает точные индексы, а не интервалы. (В качестве альтернативы вы можете сгенерировать такие концы в первую очередь)
indices=torch.stack((starts,ends-1),axis=1)
newtensor=torch.take(data,indices)
tensor([[0, 1],
[3, 4],
[4, 5],
[1, 2]])
Если вы хотите взять реальные интервалы (исходя из того, что вы назвали начало и конец индекса), это будет решением для этого:
indices=torch.stack((starts,ends),axis=1)
rangeindices=[torch.range(i[0],i[1]) for i in indices]
tensorindices=torch.stack(rangeindices).type(torch.LongTensor)
newtensor=torch.take(data,tensorindices)
tensor([[0, 1, 2],
[3, 4, 5],
[4, 5, 6],
[1, 2, 3]])
Но это (по понятным причинам) приведет к другому тензору, чем ожидаемый результат.
Обновлено:
С тех пор я нашел питонический способ для диапазонов без понимания списка! Для этого ваши концы должны быть на единицу больше, так как этот метод будет принимать диапазоны Python, которые не содержат конца диапазона.
indices=torch.stack((starts,ends),axis=1)
newtensor=torch.stack([data[slice(idx[0], idx[1])] for idx in indices])
Решение для интервалов - это именно то, что я искал. Как вы думаете, сложение индексов будет более быстрым решением по сравнению с выполнением чего-то вроде rangeindices = [torch.arange(s, e) for s, e in zip(starts, ends)] ?
Наверное, я просто не смог придумать решение, как их складывать для этой задачи
@EternalTrail Я нашел для этого меньше возможностей для понимания списка python, поэтому я отредактировал свой ответ, добавив это
Я не уверен, как функция транспонирования связана с вопросом, который я задал. Не могли бы вы уточнить?