Я изо всех сил пытался понять разницу между .clone()
, .detach()
и copy.deepcopy
при использовании Pytorch. В частности, с тензорами Pytorch.
Я попытался написать весь свой вопрос об их различиях и вариантах использования, и быстро был поражен и понял, что, возможно, наличие 4 основных свойств тензоров Pytorch намного лучше прояснит, какой из них использовать через каждый маленький вопрос. Четыре основных свойства, которые, как я понял, необходимо отслеживать:
- , если у вас есть новый указатель / ссылка на тензор
- , если у вас есть новый экземпляр объекта тензор (и, следовательно, большинство вероятно, этот новый экземпляр имеет свои собственные метаданные, такие как
require_grads
, shape, is_leaf
, et c.) - , если он выделил новую память для данных тензора (т.е. если этот новый тензор представляет собой представление другого тензора)
- отслеживает ли он историю операций или нет (или даже если он отслеживает полностью новую историю операций или ту же самую старую в случае глубокого копирования)
В соответствии с тем, что было найдено на форумах Pytorch и в документации, это мои текущие различия для каждого при использовании с тензорами:
Clone
Для клона:
x_cloned = x.clone()
Я считаю, что он ведет себя в соответствии с четырьмя основными свойствами:
- клонированный
x_cloned
имеет собственную python ссылку / указатель на новый объект - он создал свой новый тензор ob ject (с отдельными метаданными)
- он выделил новую память для
x_new
с теми же данными, что и x
- , он отслеживает оригинал история операций и, кроме того, включала эту
clone
операцию как .grad_fn=<CloneBackward>
кажется, что основное использование этого, насколько я понимаю, - это создание копий вещей, чтобы inplace_
операции безопасны. Вдобавок в сочетании с .detach
как .detach().clone()
(«лучший» порядок для этого, кстати) он создает совершенно новый тензор, который был отделен от старой истории и, таким образом, останавливает градиентный поток через этот путь.
Detach
x_detached = x.detach()
- создает новую ссылку python (единственная, которая не выполняет, конечно,
x_new = x
). Можно использовать id
для этого, я считаю, - он создал собственный новый экземпляр тензорного объекта (с его отдельными метаданными)
- ему выделено NOT новая память для
x_detached
с теми же данными, что и x - , она обрезает историю градиентов и не позволяет им проходить через нее. Я считаю правильным думать о нем как о совершенно новом тензоре, не имеющем истории.
Я считаю, что единственное разумное использование, которое я знаю, - это создание новых копий с собственной памятью в сочетании с .clone()
как .detach().clone()
. В противном случае я не уверен, для чего это нужно. Поскольку он указывает на исходные данные, выполнение операций на месте может быть потенциально опасным (поскольку оно изменяет старые данные, но изменение старых данных НЕ известно autograd в предыдущем графике вычислений).
copy.deepcopy
x_deepcopy = copy.deepcopy(x)
- если есть новый указатель / ссылка на тензор
- , он создает новый экземпляр тензора со своими собственными метаданными (все метаданных должны указывать на глубокие копии, поэтому новые объекты, если они реализованы так, как и следовало ожидать, я надеюсь).
- у него есть собственная память, выделенная для тензорных данных
- Если это действительно это глубокая копия, я ожидал бы глубокую копию истории. Так что это должно сделать глубокую репликацию истории. Хотя это кажется действительно дорогим, но, по крайней мере, семантически согласуется с тем, какой должна быть глубокая копия.
Я действительно не вижу для этого варианта использования. Я предполагаю, что любой, кто пытается использовать это, действительно имел в виду 1) .detach().clone()
или просто 2) .clone()
сам по себе, в зависимости от того, хочет ли кто-то остановить градиентные потоки к более раннему графику с 1 или если они хотят просто реплицировать данные с новым память 2).
Так что это лучший способ понять различия на данный момент, а не спрашивать все разные сценарии ios, что можно их использовать.
Так это правильно? Кто-нибудь видит какой-либо серьезный недостаток, который необходимо исправить? список распространенных вариантов использования для каждого был бы замечательным.
Ресурсы
Это все ресурсы, которые я прочитал и в которых я участвовал, чтобы прийти к выводам по этому вопросу: