Pytorch 张量中的分离、克隆和深拷贝有啥区别?

     2023-03-12     196

关键词:

【中文标题】Pytorch 张量中的分离、克隆和深拷贝有啥区别?【英文标题】:What is the difference between detach, clone and deepcopy in Pytorch tensors in detail?Pytorch 张量中的分离、克隆和深拷贝有什么区别? 【发布时间】:2020-10-07 18:35:04 【问题描述】:

在使用 Pytorch 时,我一直在努力理解 .clone().detach()copy.deepcopy 之间的区别。特别是 Pytorch 张量。

我尝试写下所有关于它们的差异和用例的问题,但很快就不知所措,并意识到也许拥有 Pytorch 张量的 4 个主要属性会更好地阐明使用哪个来解决每个小问题。我意识到需要跟踪的 4 个主要属性是:

    如果有一个张量的新指针/引用 如果有一个新的张量对象实例(因此这个新实例很可能有它自己的元数据,如require_grads、形状、is_leaf 等) 如果它为张量数据分配了新内存(即,如果这个新张量是不同张量的视图) 它是否正在跟踪操作历史记录(或者即使它正在跟踪一个全新的操作历史记录,或者在深拷贝的情况下是相同的旧历史记录)

根据从 Pytorch 论坛和文档中挖掘出来的内容,这是我目前在张量上使用时的区别:

克隆

对于克隆:

x_cloned = x.clone()

我相信这就是它根据主要 4 个属性的行为方式:

    克隆的x_cloned 有它自己的python 引用/指向新对象的指针 它创建了自己的新张量对象实例(带有单独的元数据) 它已为x_new 分配了一个新内存,其数据与x 相同 它正在跟踪原始操作历史,此外还包括此clone 操作.grad_fn=<CloneBackward>

据我所知,它的主要用途似乎是创建事物的副本,以便inplace_ 操作是安全的。此外,再加上 .detach.detach().clone() (顺便说一句“更好”的顺序),它创建了一个全新的张量,该张量已与旧历史分离,从而阻止梯度流过该路径。

分离

x_detached = x.detach()
    创建一个新的 python 引用(当然,唯一没有这样做的是x_new = x)。我相信这个可以使用id 它创建了自己的新张量对象实例(带有单独的元数据) 它没有x_detached分配了一个与x相同的数据的新内存 它切断了梯度的历史,不允许它流过它。我认为将其视为没有历史的全新张量是正确的。

我相信我所知道的唯一明智的用途是在将.clone().detach().clone() 结合使用时,使用自己的内存创建新副本。否则,我不确定它有什么用。由于它指向原始数据,因此执行就地操作可能存在潜在危险(因为它会更改旧数据,但旧数据的更改在较早的计算图中为 autograd 所知)。

copy.deepcopy

x_deepcopy = copy.deepcopy(x)
    如果有一个张量的新指针/引用 它使用自己的元数据创建一个新的张量实例(所有元数据都应指向深层副本,因此如果按照我希望的那样实现新对象)。 它为张量数据分配了自己的内存 如果它真的是一个深拷贝,我会期待一个深拷贝的历史。所以它应该对历史进行深度复制。虽然这看起来确实很昂贵,但至少在语义上与深拷贝应该是一致的。

我真的没有看到这方面的用例。我认为任何试图使用它的人真的意味着 1) .detach().clone() 或只是 2) .clone() 本身,这取决于一个人是想用 1 停止梯度流到较早的图形,还是只想用新的图形复制数据记忆 2)。

因此,这是我目前了解差异的最佳方式,而不是询问可能使用它们的所有不同场景。

所以这是对的吗?有没有人发现任何需要纠正的重大缺陷?

我自己担心的是我赋予深度复制的语义,想知道深度复制历史是否正确。

我认为每个用例的常见用例列表会很棒。


资源

这些是我阅读并参与得出此问题结论的所有资源:

0.4.0 迁移指南https://pytorch.org/blog/pytorch-0_4_0-migration-guide/ 关于使用克隆的困惑:https://discuss.pytorch.org/t/confusion-about-using-clone/39673/3 在 v0.4.0 中克隆和分离:https://discuss.pytorch.org/t/clone-and-detach-in-v0-4-0/16861/2 克隆文档: https://pytorch.org/docs/stable/tensors.html#torch.Tensor.clone 分离文档(在浏览器中搜索单词分离没有直接链接): https://pytorch.org/docs/stable/tensors.html#torch.Tensor detach().clone() 和 clone().detach() 的区别:https://discuss.pytorch.org/t/difference-between-detach-clone-and-clone-detach/34173 为什么我可以在 Pytorch 中使用 detach 来更改张量的值而计算图不知道它? Why am I able to change the value of a tensor without the computation graph knowing about it in Pytorch with detach? Pytorch 张量中 detach、clone 和 deepcopy 的区别是什么? What is the difference between detach, clone and deepcopy in Pytorch tensors in detail? Copy.deepcopy() 与 clone() https://discuss.pytorch.org/t/copy-deepcopy-vs-clone/55022/10

【问题讨论】:

类似问题的链接:***.com/questions/55266154/… 您的问题很长,也不是很清楚。使用小的编码样本会更容易。 【参考方案1】:

注意:自发布此问题以来,这些功能的行为和文档页面已更新。


torch.clone()

复制张量,同时在 autograd 图中保持链接。如果你想使用,例如将张量复制为神经网络中的操作(例如,将中级表示传递给两个不同的头以计算不同的损失):

返回输入的副本。

注意:这个函数是可微的,所以梯度会从这个运算的结果流回输入。要创建一个没有 autograd 关系的张量来输入,请参阅detach()

torch.tensor.detach()

返回没有 autograd 历史的原始张量视图。如果您想在不影响计算图的情况下操纵张量的值(未到位)(例如,在正向传递的中途报告值),则使用此方法。

返回一个新的张量,与当前图表分离。

结果永远不需要渐变。

此方法也会影响正向模式 AD 梯度,结果将永远不会有正向模式 AD 梯度。

注意:返回的张量与原始张量共享相同的存储空间。将看到对其中任何一个的就地修改,并可能触发正确性检查中的错误。 1

copy.deepcopy

deepcopy 是来自copy 库的通用 python 函数,它复制现有对象(如果对象本身包含对象,则递归)。

当您希望复制的底层对象是可变的(或包含可变的)并且容易受到镜像更改的影响时,使用此方法(与更常见的分配相反):

Python 中的赋值语句不会复制对象,它们会在目标和对象之间创建绑定。对于可变集合或包含可变项的集合,有时需要一个副本,以便可以更改一个副本而不更改另一个副本。

如您所说,在 PyTorch 设置中,如果您希望张量对象的新副本在完全不同的设置中使用,而对其父级没有任何关系或影响,您应该使用 .detach().clone()


    重要提示:以前,原地大小/步幅/存储更改(例如resize_/resize_as_/set_/transpose_)到返回的张量也会更新原始张量。现在,这些就地更改将不再更新原始张量,而是会触发错误。对于稀疏张量:对返回的张量进行就地索引/值更改(例如zero_/copy_/add_)将不再更新原始张量,而是会触发错误。

【讨论】:

PyTorch 中的 .flatten() 和 .view(-1) 有啥区别?

】PyTorch中的.flatten()和.view(-1)有啥区别?【英文标题】:Whatisthedifferencebetween.flatten()and.view(-1)inPyTorch?PyTorch中的.flatten()和.view(-1)有什么区别?【发布时间】:2019-12-0515:04:52【问题描述】:.flatten()和.view(-1)在PyTorch中展平张量。有... 查看详情

pytorch 数据加载器和/或 __getitem__ 函数中的浅拷贝和深拷贝

】pytorch数据加载器和/或__getitem__函数中的浅拷贝和深拷贝【英文标题】:shallowanddeepcopiesinpytorchdataloaderand/or__getitem__function【发布时间】:2022-01-1721:42:22【问题描述】:我在使用自定义pytorch数据加载器时遇到了问题,我认为这与... 查看详情

克隆_浅拷贝和深拷贝

...对象克隆?有两种方式:1).实现Cloneable接口并重写Object类中的clone()方法;2).实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆,代码如下: import j 查看详情

java克隆之浅拷贝和深拷贝

...中一闪而过的是“克隆羊”多利,再闪而过的是生物中的细胞有丝分裂。一个长得像,一个分裂极快。  ​在学习java设计模式,原型模式的时候,说是提供了一种机制,可以将原始对象复制到新对象,使... 查看详情

js浅拷贝(地址引用)和深拷贝(克隆)

浅拷贝和深拷贝相对于引用类型而言的。js有两大类型值类型(基本数据类型)和引用类型(object,function,array);值类型保存在栈上,引用类型保存在堆上。浅拷贝只是单纯的拷贝对象的地址。//对象的浅拷贝varaa={name:‘aa‘,a... 查看详情

原型模式(浅克隆和深克隆)

...效,或者创建值相等,只是命名不一样的同类数据.原型模式中的拷贝分为"浅拷贝"和"深拷贝":浅克隆:对值类型的成员变量进行值的复制,对引用类型的成员变量只复制引用, 查看详情

javascript中的浅拷贝和深拷贝

...拷贝和深拷贝的说法,这里简单区分一下它们在Javascript中的区别,以及jQuery中深拷贝的实现。在谈浅拷贝和深拷贝之前,先要屡清楚Javascript中的按值访问和按引用访问这两个概念。按值访问是针对基本类型(string、number、boolean... 查看详情

java对象的浅克隆和深克隆

...在Object基类中,有一个方法叫clone,产生一个前期对象的克隆,克隆对象是原对象的拷贝,由于引用类型的存在,有深克隆和浅克隆之分,若克隆对象中存在引用类型的属性,深克隆会将此属性完全拷贝一份,而浅克隆仅仅是拷... 查看详情

[记录]javascript中的深浅拷贝(克隆)

浅拷贝和深拷贝针对的是Object、Array这样复杂的引用类型数据简单说:浅拷贝只复制一层的属性,而深拷贝则递归复制所有层级的属性一、浅拷贝1functionclone(origin,target){2varresult=target||{};3for(varpropinorigin){4target[prop]=origin[prop];5}6retur... 查看详情

PyTorch LSTM 中的“隐藏”和“输出”有啥区别?

】PyTorchLSTM中的“隐藏”和“输出”有啥区别?【英文标题】:What\'sthedifferencebetween"hidden"and"output"inPyTorchLSTM?PyTorchLSTM中的“隐藏”和“输出”有什么区别?【发布时间】:2018-06-2610:25:39【问题描述】:我无法理解... 查看详情

浅拷贝和深拷贝的区别?

先考虑一种情况,对一个已知对象进行拷贝,编译系统会自动调用一种构造函数——拷贝构造函数,如果用户未定义拷贝构造函数,则会调用默认拷贝构造函数。//main.cpp#include<iostream>#include"student.h"intmain(){Students1;Students2(s1);... 查看详情

对象浅拷贝和深拷贝有什么区别(代码片段)

...变量的值,而引用类型拷贝的其实是变量的地址而浅拷贝和深拷贝就是在这个基础之上做的区分,如果在拷贝这个对象的时候,只对基本数据类型进行了拷贝,而对引用数据类型只是进行了引用的传递,而没有重新创建一个新的... 查看详情

PyTorch 中的 index_select 和 tensor[sequence] 之间有啥区别吗?

】PyTorch中的index_select和tensor[sequence]之间有啥区别吗?【英文标题】:Isthereanydiffrencebetweenindex_selectandtensor[sequence]inPyTorch?PyTorch中的index_select和tensor[sequence]之间有什么区别吗?【发布时间】:2020-04-0805:10:38【问题描述】:每个人... 查看详情

PyTorch 中的 register_parameter 和 register_buffer 有啥区别?

】PyTorch中的register_parameter和register_buffer有啥区别?【英文标题】:Whatisthedifferencebetweenregister_parameterandregister_bufferinPyTorch?PyTorch中的register_parameter和register_buffer有什么区别?【发布时间】:2019-12-2317:30:07【问题描述】:模块的para... 查看详情

pytorch之张量的相关介绍(代码片段)

...I创建tensortorch.Tensor和torch.tensor的区别torch.Tensortorch.tensor()Pytorch中tensor的常用方法获取tensor中的数据(当tensor中只有一个元素可用):tensor.it 查看详情

pytorch中张量加法赋值和赋值的区别

】pytorch中张量加法赋值和赋值的区别【英文标题】:Differencebetweentensoradditionassignmentandassignmentinpytorch【发布时间】:2021-10-0610:55:01【问题描述】:我发现pytorch对待张量赋值和加法赋值的方式不同。示例如下所示x=torch.tensor(3.0)pri... 查看详情

python中的赋值,浅拷贝和深拷贝的区别

赋值(=),就是创建了对象的一个新的引用,修改其中任意一个变量都会影响到另一个。浅拷贝:创建一个新的对象,但它包含的是对原始对象中包含项的引用(如果用引用的方式修改其中一个对象,另外一个也会修改改变)1,完全... 查看详情

C中的浅拷贝和深拷贝

】C中的浅拷贝和深拷贝【英文标题】:ShallowcopyanddeepcopyinC【发布时间】:2013-03-0717:49:31【问题描述】:我尝试用谷歌搜索,但只弹出面向对象的语言作为结果。据我了解,浅拷贝是复制结构的某些成员。所以我们说一个结构是t... 查看详情