一、tensor.data的使用 (属性)
import torch
a = torch.tensor([1,2,3.], requires_grad = True)
out = a.sigmoid()
c = out.data # 通过.data “分离”得到的的变量会和原来的变量共用数据(指向同一地址),而且新分离得到的张量是不可求导的
c.zero_() # 改变c的值,原来的out也会改变
print(c.requires_grad) #false
print(c) #tensor([0., 0., 0.])
print(out.requires_grad) #True
print(out) #tensor([0., 0., 0.], grad_fn=)
print("----------------------------------------------")
out.sum().backward() # 对原来的out求导,
print(a.grad) # 不会报错,但是结果却并不正确
.data的两点总结:
(1)tensor .data 将返回相同数据的 tensor,而且两个tensor共用数据,一者改变,另一者也会跟着改变。新分离得到的tensor的require s_grad = False, 即不可求导的。(这一点其实detach是一样的)
(2)使用tensor.data的局限性。文档中说使用tensor.data是不安全的, 因为 x.data 不能被 autograd 追踪求微分 。什么意思呢?从上面的例子可以看出,由于我更改分离之后的变量值c,导致原来的张量out的值也跟着改变了,但是这种改变对于autograd是没有察觉的,它依然按照求导规则来求导,导致得出完全错误的导数值却浑然不知。它的风险性就是如果我再任意一个地方更改了某一个张量,求导的时候也没有通知我已经在某处更改了,导致得出的导数值完全不正确,故而风险大。这种方式已经基本被淘汰了。
二、detach() (方法)
import torch
a = torch.tensor([1,2,3.], requires_grad = True)
out = a.sigmoid()
c = out.detach() # 通过.detach() “分离”得到的的变量也会与原张量使用同一数据,而且新分离得到的张量是不可求导的
c.zero_() # 改变c的值,原来的out也会改变
print(c.requires_grad) #false
print(c) #tensor([0., 0., 0.])
print(out.requires_grad) #true
print(out) #tensor([0., 0., 0.], grad_fn=)
print("----------------------------------------------")
out.sum().backward() # 对原来的out求导,
print(a.grad) # 此时会报错,监测到梯度计算所需要的张量已经被“原位操作inplace”所更改了
detach()的两点总结:
(1)tensor.detach() 将返回相同数据的 tensor,而且两个tensor共用数据,一者改变,另一者也会跟着改变。新分离得到的tensor的require s_grad = False, 即不可求导的。(这一点和.data是一样的)
(2)使用tensor.detach()的优点。从上面的例子可以看出,detach存在监测机制。由于我更改分离之后的变量值c,导致原来的张量out的值也跟着改变了,这个时候如果依然按照求导规则来求导肯定会错误,所以不会再继续求导了。
三、requires_grad_()
需要注意的是,这个是函数,与requires_grad属性不同。
这个函数的作用是改变requires_grad属性并返回tensor,修改requires_grad属性是inplace操作,默认参数为requires_grad=True。
注意:只开不关
四、torch.no_grad()
用来禁止梯度的计算,常用在网络推断。
被with torch.no_grad包起来的操作,仍会运行或计算,但是他们的requires_grad属性会被赋为False。从而在计算图中关闭这些操作的梯度计算。
当不需要进行反向传播或梯度计算时,requires_grad=True的变量会占用很多计算资源及存储资源。with torch.no_grad作用范围中的操作不会构建计算图。
参考:https://blog.csdn.net/qq_27825451/article/details/96837905