detach操作相当于深度拷贝——返回一个不同内存空间的新变量充当叶子节点

Posted MarToony|名角

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了detach操作相当于深度拷贝——返回一个不同内存空间的新变量充当叶子节点相关的知识,希望对你有一定的参考价值。

pytorch.deatch()方法的结论与代码证明。

  • datach操作,相当于一个深度拷贝,操作后返回的变量和被detach的节点不属于同一个内存id,同时之后,被detach的节点的内容被修改后,返回的变量不会随之更改。
  • detach操作后返回的变量默认不进行梯度计算,因此如果希望计算该叶子节点,则需要指定其梯度计算属性。
import torch

A = torch.Tensor([1, 1., 2, 3])
B = torch.Tensor([1, 1, 1, 1])
A.requires_grad_(True)
B.requires_grad_(True)
C = A + B

E = C.detach()
F = C.detach()

E.requires_grad_(True)

D = C * A * E * F
print("C, E, F:\\n", C, E, F)

D.sum().backward()
print(A.grad)
print(B.grad)

# EF的不同在于E被指定了计算梯度值,当作一个可计算梯度的叶子节点;
# 如果未指定,则就是作为一个标量,对计算有贡献,但是并不需要计算梯度。
print(E.grad)
print(F.grad)

# 1 非叶子节点不存在梯度值,特征X是,每一层的权重也是叶子;
# 2 deatch前后获得的数据是同id吗?不同;而这种detach是一种深拷贝,当然它因为是torch中的行为,因此还具有其他的功能。

C = A
# 如果输出与上面的EF值相同,且不同于变换后的C值,那就表明detach操作是一种深度拷贝。任何一方的操作不会引起另一方的数值变换。
print(id(C), id(E), id(F))
print("C, E, F:\\n", C, E, F)
# ----------------------------
"""
C, E, F:
tensor([2., 2., 3., 4.], grad_fn=<AddBackward0>) tensor([2., 2., 3., 4.], requires_grad=True) tensor([2., 2., 3., 4.])
tensor([ 12.,  12.,  45., 112.])
tensor([ 4.,  4., 18., 48.])
tensor([ 4.,  4., 18., 48.])
None
-----------------------------
140374691657088 140380286141312 140380286141376
C, E, F:
 tensor([1., 1., 2., 3.], requires_grad=True) tensor([2., 2., 3., 4.], requires_grad=True) tensor([2., 2., 3., 4.])
"""

以上是关于detach操作相当于深度拷贝——返回一个不同内存空间的新变量充当叶子节点的主要内容,如果未能解决你的问题,请参考以下文章

内存拷贝

C++中的深拷贝和浅拷贝构造函数

vue组件间传递对象的深拷贝

String 类的实现深度拷贝详解

89.赋值重载以及深浅拷贝

String 类的实现浅拷贝存在的问题