pytorch .detach() .detach_() 和 .data 切断反向传播

pytorch .detach().detach_()和 .data 切断反向传播

当我们再训练网络的时候可能希望保持一部分的网络参数不变,只对其中一部分的参数进行调整;或者只训练部分分支网络,并不让其梯度对主网络的梯度造成影响,这时候我们就需要使用detach()函数来切断一些分支的反向传播。
不过在查看前人写的一些代码时,经常会看见.data,下面介绍一下区别:

.data

import torch
a = torch.tensor([1,2,3.], requires_grad =True)
out = a.sigmoid()
c = out.data  #c取出out的tensor之后  require s_grad = False
print(out.requires_grad)
print(c.requires_grad)
print(c.zero_())  #改变c也会改变out 但是通过c改变out的值并不能被autograd追踪求微分
print(out)   
out.sum().backward()   #但却会影响out的求导 不给出报错
print(a.grad)    # 这个结果很严重的错误,因为out已经改变了

True
False
tensor([0., 0., 0.])
tensor([0., 0., 0.], grad_fn=)
tensor([0., 0., 0.]) //这是一个不应该计算出来的错误结果

.detach()

c = out.detach()  #c取出out的tensor之后  require s_grad = False
print(out.requires_grad)
print(c.requires_grad)
print(c.zero_()) #改变c也会改变out 但是通过c改变out的值 能被autograd追踪 
print(out)   
out.sum().backward() #会影响out的求导 但会给出报错  如果注释掉c.zero_()就不会出错,也不会报错啦
print(a.grad)

True
False
tensor([0., 0., 0.])
tensor([0., 0., 0.], grad_fn=)
RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation: [torch.FloatTensor [3]], which is output 0 of SigmoidBackward, is at version 1; expected version 0 instead. Hint: enable anomaly detection to find the operation that failed to compute its gradient, with torch.autograd.set_detect_anomaly(True).

注:就算后面更改了c的require s_grad也是不能成功求导的。

.detach_()

c = out.detach_()  #c取出out的tensor之后  require s_grad = False
print(out.requires_grad)
print(c.requires_grad)
print(c.zero_()) #改变c也会改变out 但是通过c改变out的值 能被autograd追踪 
print(out)   
out.sum().backward() #会影响out的求导
print(a.grad)

False
False
tensor([0., 0., 0.])
tensor([0., 0., 0.])
RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn

总结

总而言之,.data是以前老版本的使用方法,现在使用.detach()就好啦。.detach()从当前计算图中分离下来的,但是仍指向原变量的存放位置,同之处只是requires_grad为false,得到的这个Variable永远不需要计算其梯度,不具有grad。进行反向传播时,到该调用detach()的Variable就会停止,不能再继续向前进行传播。可见函数进行的操作有:将grad_fn设置为None 将Variable的requires_grad设置为False。
detach()和detach_()很像,两个的区别就是detach_()是对本身的更改,detach()则是生成了一个新的变量,比如x->m->y中如果对m进行detach(),后面如果反悔想还是对原来的计算图进行操作还是可以的。但是如果是进行了detach_(),那么原来的计算图也发生了变化,x->m->y直接变成了x, m->y。

补充:.clone()

c = out.clone()  #c取出out的tensor之后  require s_grad = Ture
print(out.requires_grad)
print(c.requires_grad)
print(c.zero_()) #改变c也会改变out 但是通过c改变out的值 能被autograd追踪 
print(out)   
out.sum().backward() #会影响out的求导 但是正确的
print(a.grad)

True
True
tensor([0., 0., 0.], grad_fn=)
tensor([0.7311, 0.8808, 0.9526], grad_fn=)
tensor([0.1966, 0.1050, 0.0452])

.clone()的数据require s_grad = Ture,改变c也会改变out,同时能够将梯度进行传播。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值