Вид на порцию тензора - PullRequest
       0

Вид на порцию тензора

2 голосов
/ 11 февраля 2020

У меня есть тензор нескольких измерений, давайте возьмем этот простой пример:

out = torch.Tensor(3, 4, 5)

Мне нужно получить часть / часть этого тензора out[:,0,:], а затем применить метод view(-1), но это невозможно:

 out[:,0,:].view(-1)

RuntimeError: invalid argument 2: view size is not compatible with input tensor's size and stride (at least one dimension spans across two contiguous subspaces). Call .contiguous() before .view(). at ../aten/src/TH/generic/THTensor.cpp:203

Решение состоит в том, чтобы клонировать подраздел:

 out[:,0,:].clone().view(-1)

Есть ли лучшее / более быстрое решение, чем клонирование?

1 Ответ

2 голосов
/ 11 февраля 2020

То, что вы сделали, будет работать нормально. Тем не менее, более переносимым подходом будет использование reshape, которое будет возвращать представление, когда это возможно, но будет создавать непрерывную копию при необходимости. Таким образом, он сделает все возможное. В вашем случае данные должны быть скопированы, но всегда используя reshape, есть случаи, когда копия не будет создана.

Так что вы можете использовать

out[:,0,:].reshape(-1)

Попался

Здесь есть одна важная ошибка. Если вы выполняете операции на месте для вывода reshape, то это может повлиять или не повлиять на исходный тензор в зависимости от того, было ли возвращено представление или копия.

Например, предполагая out уже является смежным, тогда в этом случае

>>> x = out[:,0,:].reshape(-1)    # returns a copy
>>> x[0] = 10
>>> print(out[0,0,0].item() == 10)
False

x является копией, поэтому изменения в ней не влияют на out. Но в этом случае

>>> x = out[:,:,0].reshape(-1)     # returns a view
>>> x[0] = 10
>>> print(out[0,0,0].item() == 10)
True

x является представлением, поэтому изменения на месте на x также изменят out.


Альтернативы

Альтернативой пары являются

out[:,0,:].flatten()    # .flatten is just a special case of .reshape

и

out[:,0,:].contiguous().view(-1)

Хотя, если вы хотите самый быстрый подход, я рекомендую против последнего метода, использующего contiguous().view, поскольку, как правило, более вероятно, чем reshape или flatten, чтобы вернуть копию. Это связано с тем, что contiguous создаст копию, даже если базовые данные имеют одинаковое количество байтов между последующими записями. Следовательно, существует разница между

out[:,:,0].contiguous().view(-1)       # creates a copy

и

out[:,:,0].flatten()                   # creates a non-contiguous view (b/c underlying data has uniform spacing of out.shape[2] values between entries)

, когда подход contiguous().view приводит к принудительному копированию, поскольку out[:,:,0] не является смежным, а flatten / reshape создаст представление, поскольку базовые данные расположены равномерно.

Иногда contiguous() не создает копию, например, сравнивает

out[0,:,:].contiguous().view(-1)       # creates a view b/c out[0,:,:] already is contiguous

и

out[0,:,:].flatten()                   # creates a view

которые оба производят просмотр исходных данных без копирования, так как out[0,:,:] уже является смежным.


Если вы хотите убедиться, что out полностью отделен от сплющенного аналога, тогда исходный подход использование .clone() - это путь к go.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...