-
pytorch tensor 中的
.clone()
和.detach()
在写代码时经常能见到通过
tensor.detach().clone()
操作生成一个和原本 tensor 值相同的新 tensor为什么需要同时使用
.clone()
和.detach()
,接下来通过代码进行说明-
生成两个 tensor,并且求梯度
a = torch.tensor([1.0, 1.0], requires_grad=True) b = torch.tensor([2.0, 2.0], requires_grad=True) loss = a@b loss.backward() print(a, b) print(a.grad, b.grad)
输出结果:
tensor([1., 1.], requires_grad=True) tensor([2., 2.], requires_grad=True)
tensor([2., 2.]) tensor([1., 1.])可以看到 a, b 的梯度分别为 [2., 2.],[1., 1.]
-
使用 a_=a.detch() 脱离计算图
在上面的代码中加上
a_=a.detch()
并且使用a_
计算和 backward()a = torch.tensor([1.0, 1.0], requires_grad=True) b = torch.tensor([2.0, 2.0], requires_grad=True) a_ = a.detach() loss = a_@b loss.backward() print(a, b) print(a.grad, b.grad)
输出结果:
tensor([1., 1.], requires_grad=True) tensor([2., 2.], requires_grad=True)
None tensor([1., 1.])此时 a 的梯度为 none,因为
.detach()
生成了一个新的 tensor 并且从计算图中脱离。a_
运算后产生的梯度并不会传回a
关于
detach()
具体细节可以查询官方文档生成的 a_ 是不会计算梯度的:
print(a_.requires_grad) # out: False
-
需要注意的是 .detach() 生成的 tensor 和原本的 tensor 共享内存
a = torch.tensor([1.0, 1.0], requires_grad=True) b = torch.tensor([2.0, 2.0], requires_grad=True) a_ = a.detach() # 对 a_ 修改 a_[0] +=2 loss = a@b loss.backward() print(a, b) print(a.grad, b.grad)
输出:
tensor([3., 1.], requires_grad=True) tensor([2., 2.], requires_grad=True)
tensor([2., 2.]) tensor([3., 1.])可以看到 a, b 的梯度分别为 [2., 2.],[3., 1.],原本a, b 的梯度分别为 [2., 2.],[1., 1.],但是因为改变了 a_[0],导致 a[0] 也变了,所以梯度也发生了变化。
上面的代码中,通过
.detach()
生成了新的 tensor,然后修改新生成的 tensor。在计算原本 a@b 的backward() 发现 b 的梯度发生了变化。这是因为修改了 a_ 的同时 a 也发生了变换。所以需要.clone()
-
使用
.clone()
生成新的 tensora = torch.tensor([1.0, 1.0], requires_grad=True) b = torch.tensor([2.0, 2.0], requires_grad=True) a_ = a.clone() a_[0] +=2 loss = a@b loss.backward() print(a, b) print(a.grad, b.grad)
输出:
tensor([1., 1.], requires_grad=True) tensor([2., 2.], requires_grad=True)
tensor([2., 2.]) tensor([1., 1.])上述代码中,
a_
由a.clone()
生成。对a_
进行修改并不会影响原本的a
-
.clone()
和.detach()
.clone()
生成的 tensor 是可微的,在 backward 时候会将梯度回传在官方文档-clone() 中提到
This function is differentiable, so gradients will flow back from the result of this operation to input. To create a tensor without an autograd relationship to input see detach().
a = torch.tensor([1.0, 1.0], requires_grad=True) b = torch.tensor([2.0, 2.0], requires_grad=True) a_ = a.clone() a_[0] +=2 loss = a_@b loss.backward() print(a, b) print(a.grad, b.grad)
tensor([1., 1.], requires_grad=True) tensor([2., 2.], requires_grad=True)
tensor([2., 2.]) tensor([3., 1.])可以看到,
b
的梯度是 [3., 1.] 而不是 [1., 1.]这是因为使用
.clone()
生成的 tensor 进行运算,反向求导产生的梯度会传回输入节点。所以一般
.clone()
和.detach()
需要配合使用
-
pytorch 中的 .detach() .clone()
最新推荐文章于 2024-04-17 11:23:00 发布