В чем разница между detach, clone и deepcopy в тензорах Pytorch в деталях? - PullRequest
1 голос
/ 17 июня 2020

Я изо всех сил пытался понять разницу между .clone(), .detach() и copy.deepcopy при использовании Pytorch. В частности, с тензорами Pytorch.

Я попытался написать весь свой вопрос об их различиях и вариантах использования, и быстро был поражен и понял, что, возможно, наличие 4 основных свойств тензоров Pytorch намного лучше прояснит, какой из них использовать через каждый маленький вопрос. Четыре основных свойства, которые, как я понял, необходимо отслеживать:

  1. , если у вас есть новый указатель / ссылка на тензор
  2. , если у вас есть новый экземпляр объекта тензор (и, следовательно, большинство вероятно, этот новый экземпляр имеет свои собственные метаданные, такие как require_grads, shape, is_leaf, et c.)
  3. , если он выделил новую память для данных тензора (т.е. если этот новый тензор представляет собой представление другого тензора)
  4. отслеживает ли он историю операций или нет (или даже если он отслеживает полностью новую историю операций или ту же самую старую в случае глубокого копирования)

В соответствии с тем, что было найдено на форумах Pytorch и в документации, это мои текущие различия для каждого при использовании с тензорами:

Clone

Для клона:

x_cloned = x.clone()

Я считаю, что он ведет себя в соответствии с четырьмя основными свойствами:

  1. клонированный x_cloned имеет собственную python ссылку / указатель на новый объект
  2. он создал свой новый тензор ob ject (с отдельными метаданными)
  3. он выделил новую память для x_new с теми же данными, что и x
  4. , он отслеживает оригинал история операций и, кроме того, включала эту clone операцию как .grad_fn=<CloneBackward>

кажется, что основное использование этого, насколько я понимаю, - это создание копий вещей, чтобы inplace_ операции безопасны. Вдобавок в сочетании с .detach как .detach().clone() («лучший» порядок для этого, кстати) он создает совершенно новый тензор, который был отделен от старой истории и, таким образом, останавливает градиентный поток через этот путь.

Detach

x_detached = x.detach()
  1. создает новую ссылку python (единственная, которая не выполняет, конечно, x_new = x). Можно использовать id для этого, я считаю,
  2. он создал собственный новый экземпляр тензорного объекта (с его отдельными метаданными)
  3. ему выделено NOT новая память для x_detached с теми же данными, что и x
  4. , она обрезает историю градиентов и не позволяет им проходить через нее. Я считаю правильным думать о нем как о совершенно новом тензоре, не имеющем истории.

Я считаю, что единственное разумное использование, которое я знаю, - это создание новых копий с собственной памятью в сочетании с .clone() как .detach().clone(). В противном случае я не уверен, для чего это нужно. Поскольку он указывает на исходные данные, выполнение операций на месте может быть потенциально опасным (поскольку оно изменяет старые данные, но изменение старых данных НЕ известно autograd в предыдущем графике вычислений).

copy.deepcopy

x_deepcopy = copy.deepcopy(x)
  1. если есть новый указатель / ссылка на тензор
  2. , он создает новый экземпляр тензора со своими собственными метаданными (все метаданных должны указывать на глубокие копии, поэтому новые объекты, если они реализованы так, как и следовало ожидать, я надеюсь).
  3. у него есть собственная память, выделенная для тензорных данных
  4. Если это действительно это глубокая копия, я ожидал бы глубокую копию истории. Так что это должно сделать глубокую репликацию истории. Хотя это кажется действительно дорогим, но, по крайней мере, семантически согласуется с тем, какой должна быть глубокая копия.

Я действительно не вижу для этого варианта использования. Я предполагаю, что любой, кто пытается использовать это, действительно имел в виду 1) .detach().clone() или просто 2) .clone() сам по себе, в зависимости от того, хочет ли кто-то остановить градиентные потоки к более раннему графику с 1 или если они хотят просто реплицировать данные с новым память 2).

Так что это лучший способ понять различия на данный момент, а не спрашивать все разные сценарии ios, что можно их использовать.

Так это правильно? Кто-нибудь видит какой-либо серьезный недостаток, который необходимо исправить? список распространенных вариантов использования для каждого был бы замечательным.

Ресурсы

Это все ресурсы, которые я прочитал и в которых я участвовал, чтобы прийти к выводам по этому вопросу:

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