Какая разница между изменением формы и представлением в pytorch?
В numpy мы используем ndarray.reshape()
для перестройки массива.
Я заметил, что в pytorch люди используют torch.view(...)
для той же цели, но в то же время существует также torch.reshape(...)
.
Поэтому мне интересно, какие различия между ними и когда я должен использовать любой из них?
Ответы
Ответ 1
torch.view
существует уже давно. Он вернет тензор с новой формой. Возвращенный тензор поделится подчиненными данными с исходным тензором. Смотрите документацию здесь.
С другой стороны, похоже, что torch.reshape
был недавно представлен в версии 0.4. Согласно документу, этот метод будет
Возвращает тензор с теми же данными и количеством элементов, что и на входе, но с заданной формой. Когда это возможно, возвращенный тензор будет отображать входные данные. В противном случае это будет копия. Смежные входы и входы с совместимыми шагами могут быть изменены без копирования, но вы не должны зависеть от поведения копирования и просмотра.
Это означает, что torch.reshape
может вернуть копию или представление оригинального тензора. Вы не можете рассчитывать на то, чтобы вернуть представление или копию. По словам разработчика:
если вам нужна копия, используйте clone(), если вам нужно то же хранилище, используйте view(). Семантика reshape() заключается в том, что он может или не может совместно использовать хранилище, и вы не знаете заранее.
Ответ 2
Хотя и torch.view
и torch.reshape
используются для изменения тензоров, здесь есть различия между ними.
- Как следует из названия,
torch.view
просто создает представление оригинального тензора. Новый тензор всегда будет делиться своими данными с оригинальным тензором. Это означает, что если вы измените исходный тензор, измененный тензор изменится, и наоборот.
>>> z = torch.zeros(3, 2)
>>> x = z.view(2, 3)
>>> z.fill_(1)
>>> x
tensor([[1., 1., 1.],
[1., 1., 1.]])
- Чтобы новый тензор всегда
torch.view
своими данными с оригиналом, torch.view
накладывает некоторые ограничения на смежность форм двух тензоров [ docs ]. Чаще всего это не проблема, но иногда torch.view
выдает ошибку, даже если формы двух тензоров совместимы. Вот знаменитый контрпример.
>>> z = torch.zeros(3, 2)
>>> y = z.t()
>>> y.size()
torch.Size([2, 3])
>>> y.view(6)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
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().
-
torch.reshape
не накладывает никаких ограничений на смежность, но также не гарантирует совместное использование данных. Новый тензор может быть представлением оригинального тензора или может быть новым тензором в целом.
>>> z = torch.zeros(3, 2)
>>> y = z.reshape(6)
>>> x = z.t().reshape(6)
>>> z.fill_(1)
tensor([[1., 1.],
[1., 1.],
[1., 1.]])
>>> y
tensor([1., 1., 1., 1., 1., 1.])
>>> x
tensor([0., 0., 0., 0., 0., 0.])
TL; DR:
Если вы просто хотите изменить форму тензоров, используйте torch.reshape
. Если вы также обеспокоены использованием памяти и хотите, чтобы два тензора совместно использовали одни и те же данные, используйте torch.view
.
Ответ 3
Tensor.reshape()
является более надежным. Он будет работать с любым тензором, тогда как Tensor.view()
работает только с тензором t
где t.is_contiguous()==True
.
t.contiguous()
несмежных и смежных событий - другая история времени, но вы всегда можете сделать непрерывный тензор t
вы вызываете t.contiguous()
а затем можете вызвать view()
без ошибки.