Pytorch中.detach()与.data的用法小结
Pytorch中.detach()与.data的用法
这里是官方文档对detach的定义
实际上,detach()就是返回一个新的tensor,并且这个tensor是从当前的计算图中分离出来的。但是返回的tensor和原来的tensor是共享内存空间的。
import torch a = torch.tensor([1.0, 2.0, 3.0], requires_grad = True) a = a.detach() # 会将requires_grad 属性设置为False print(a.requires_grad)
举个例子来说明一下detach有什么用。 如果A网络的输出被喂给B网络作为输入, 如果我们希望在梯度反传的时候只更新B中参数的值,而不更新A中的参数值,这时候就可以使用detach()
a = A(input) a = a.deatch() # 或者a.detach_()进行in_place操作 out = B(a) loss = criterion(out, labels) loss.backward()
如果希望修改A的参数, 而不希望修改B的参数, 那么就需要手动将B中参数的requires_grad属性设置为False
for param in B.parameters(): param.requires_grad = False
还有一点需要注意的是Tensor.detach()和Tensor.data的区别
Tensor.data和Tensor.detach()一样, 都会返回一个新的Tensor, 这个Tensor和原来的Tensor共享内存空间,一个改变,另一个也会随着改变,且都会设置新的Tensor的requires_grad属性为False。这两个方法只取出原来Tensor的tensor数据, 丢弃了grad、grad_fn等额外的信息。区别在于Tensor.data不能被autograd追踪到,如果你修改了Tensor.data返回的新Tensor,原来的Tensor也会改变, 但是这时候的微分并没有被追踪到,那么当你执行loss.backward()的时候并不会报错,但是求的梯度就是错误的!因此, 如果你使用了Tensor.data,那么切记一定不要随便修改返回的新Tensor的值。如果你使用的是Tensor.detach()方法,当你修改他的返回值并进行求导操作,会报错。 因此,Tensor.detach()是安全的。
pytorch中的.detach和.data深入详解
前言:这两个方法都可以用来从原有的计算图中分离出某一个tensor,有相似的地方,也有不同的地方,下面来比较性的看一看。PyTorch0.4以及之后的版本中,.data 仍保留,但建议使用 .detach()
一、tensor.data的使用
先直接看一段代码:
import torch a = torch.tensor([1,2,3.], requires_grad = True) out = a.sigmoid() c = out.data # 需要走注意的是,通过.data “分离”得到的的变量会和原来的变量共用同样的数据,而且新分离得到的张量是不可求导的,c发生了变化,原来的张量也会发生变化 c.zero_() # 改变c的值,原来的out也会改变 print(c.requires_grad) print(c) print(out.requires_grad) print(out) print("----------------------------------------------") out.sum().backward() # 对原来的out求导, print(a.grad) # 不会报错,但是结果却并不正确 '''运行结果为: False tensor([0., 0., 0.]) True tensor([0., 0., 0.], grad_fn=<SigmoidBackward>) ---------------------------------------------- tensor([0., 0., 0.]) '''
tensor.data的两点总结:
(1)tensor .data 返回和 x 的相同数据 tensor,而且这个新的tensor和原来的tensor是共用数据的,一者改变,另一者也会跟着改变,而且新分离得到的tensor的require s_grad = False, 即不可求导的。(这一点其实detach是一样的)
(2)使用tensor.data的局限性。文档中说使用tensor.data是不安全的, 因为 x.data 不能被 autograd 追踪求微分 。什么意思呢?从上面的例子可以看出,由于我更改分离之后的变量值c,导致原来的张量out的值也跟着改变了,但是这种改变对于autograd是没有察觉的,它依然按照求导规则来求导,导致得出完全错误的导数值却浑然不知。它的风险性就是如果我再任意一个地方更改了某一个张量,求导的时候也没有通知我已经在某处更改了,导致得出的导数值完全不正确,故而风险大。
二、tensor.detach()的使用
同样是使用上面的案例代码,将.data 更改成 .detach,如下:
import torch a = torch.tensor([1,2,3.], requires_grad = True) out = a.sigmoid() c = out.detach() # 需要走注意的是,通过.detach() “分离”得到的的变量会和原来的变量共用同样的数据,而且新分离得到的张量是不可求导的,c发生了变化,原来的张量也会发生变化 c.zero_() # 改变c的值,原来的out也会改变 print(c.requires_grad) print(c) print(out.requires_grad) print(out) print("----------------------------------------------") out.sum().backward() # 对原来的out求导, print(a.grad) # 此时会报错,错误结果参考下面,显示梯度计算所需要的张量已经被“原位操作inplace”所更改了。 ''' False tensor([0., 0., 0.]) True tensor([0., 0., 0.], grad_fn=<SigmoidBackward>) ---------------------------------------------- RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation '''
tensor.detach()的两点总结:
(1)tensor .detach() 返回和 x 的相同数据 tensor,而且这个新的tensor和原来的tensor是共用数据的,一者改变,另一者也会跟着改变,而且新分离得到的tensor的require s_grad = False, 即不可求导的。(这一点其实 .data是一样的)
(2)使用tensor.detach()的优点。从上面的例子可以看出,由于我更改分离之后的变量值c,导致原来的张量out的值也跟着改变了,这个时候如果依然按照求导规则来求导,由于out已经更改了,所以不会再继续求导了,而是报错,这样就避免了得出完全牛头不对马嘴的求导结果。
三、总结
相同点:tensor.data和tensor.detach() 都是变量从图中分离,但而这都是“原位操作 inplace operation”。
不同点:
(1).data 是一个属性,二.detach()是一个方法;
(2).data 是不安全的,.detach()是安全的。
到此这篇关于Pytorch中.detach()与.data的用法的文章就介绍到这了,更多相关Pytorch中.detach()与.data内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
最新评论