Pytorch 梯度、求导相关

计算图、叶子节点 和 计算节点

计算图:如下图所示,圆圈中的为数(Tensor或常数),方块中的为操作

叶子节点:不依赖于其他数的数,即没有前驱,如图中的w,x,b

计算节点:依赖于其他数计算得来的数,如图中的y

张量: torch.Tensor和torch.tensor()

区别:Tensor是一个类,所有tensor都是其实例,tensor()是一个函数。使用二者创建的tensor实例的默认dtype不同

import torch

x = torch.Tensor([2, 3])
print(x.dtype)  # torch.float32

x = torch.tensor([2, 3])
print(x.dtype)  # torch.int64

每个tensor实例都有data、grad、grad_fn、requires_grad这几个属性:

data:就是tensor实例中存的数据,它的类型也为Tensor

grad:tensor实例中存的其对应梯度,只有叶子节点的grad在backward时会被保存(计算节点的grad始终为None)

grad_fn:存得到该tensor实例所执行的操作,在backward时起作用。叶子节点的grad_fn为None,grad_fn在计算节点中被自动跟踪记录(如果没有额外指明不跟踪的话,下面会说)

requires_grad:该tensor是否需要求梯度,叶子节点的requires_grad可以自行指定,计算节点的requires_grad值是自动根据其依赖的节点得来的,即如果其依赖的节点中有requires_grad=True的,那该计算节点的requires_grad值就自动为True(计算节点的requires_grad若得到为True,不可以将其显式修改为False,除非将该节点从计算图拆卸下来,下面会说)

# 叶子节点(tensor)的初始化
import torch
import numpy as np

# 方式一
x = torch.randn(2,2, requires_grad=True)  # 2*2随机矩阵

# 方式二
x = torch.autograd.Variable(torch.Tensor([2,3]), requires_grad=True)  # 向量[2, 3]

#方式三
x = torch.tensor([2,3], requires_grad=True, dtype=torch.float64)

# 方式四
x = np.array([1,2,3] ,dtype=np.float64)
x = torch.from_numpy(x)
x.requires_grad = True
# 或者 x.requires_grad_(True)


# 说明:只有float类型的数才有梯度,故需要指明dtype为float

节点拆卸:detach()与detach_()

tensor实例的成员方法

作用:顾名思义,将某一节点拆卸下来,如图所示,执行y.detach_()后,y.grad_fn=None,y.requires_grad=False,w.backward()时梯度将无法回传至y(更无法往前传):

区别:y.detach()不会改变y,而是会返回一个y的副本(y的一个引用,指向内存中的同一片数据区域),但此副本的grad_fn=None,requires_grad=False;y.detach_()会直接改变y的grad_fn和requires_grad,没有返回值

tensor实例的.data属性和.detach()方法的作用是一样的,但用.detach()更安全,详见:

tensor.detach() 和 tensor.data 的区别_AI界扛把子的博客-CSDN博客_tensor.data

with torch.set_grad_enabled(False):与with torch.no_grad():

二者等价。

作用:取消对计算操作的跟踪。with块下定义的所有节点的requires_grad都为False,grad_fn都为None(相当于with块中定义的所有节点都被detach了)。注意该语句不改变with块外定义的节点的requires_grad和grad_fn

区分:model.eval():

model.eval()起不到with torch.set_grad_enable(False)/with torch.no_grad()的作用(即取消跟踪),会计算梯度但是不会进行优化。它的作用还包括改变dropout层和batchnorm层的行为以用于模型评估,详见:

pytorch 中 torch.no_grad()、requires_grad、eval()[Python常见问题]-云海天教程 (yht7.com)

梯度反向传播:.backward()

注意事项:

①如果想重复执行多次.backward(),则每次需要使用.backward(retain_graph=True)

②完成一次反向传播后,需要将叶子节点的grad清零,如x.grad.zero_(),否则之后再对x进行求导时会将求出来的梯度累加到之前的grad上面

参考:

pytorch的梯度计算以及backward方法_步步拾遗-CSDN博客_pytorch 梯度

pytorch中的model.eval() 和model.train()以及with torch.no_grad 还有torch.set_grad_enabled总结_a250225的博客-CSDN博客

https://discuss.pytorch.org/t/confused-about-set-grad-enabled/38417

Pytorch自动求导_qq_41533576-CSDN博客

pytorch反向传播自动求导_cobracanary的博客-CSDN博客

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值