栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

通俗讲解Pytorch梯度的相关问题:计算图、with torch.no

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

通俗讲解Pytorch梯度的相关问题:计算图、with torch.no

文章目录
      • with torch.no_grad()和requires_grad
      • backward()
      • Variable,Parameter和torch.tensor()
      • zero_grad()
      • 计算图
      • with torch.no_grad()和backward()

既然涉及梯度,不得不先谈谈requires_grad。

import torch
with torch.no_grad()和requires_grad

下面先来做做题:

a=torch.tensor([1.1])
print(a.requires_grad)
#答案是?
a=torch.tensor([1.1],requires_grad=True)
b=a*2
print(b.requires_grad)
#答案是?
a=torch.tensor([1.1],requires_grad=True)
with torch.no_grad():
    b=a*2
print(a.requires_grad)
print(b.requires_grad)
#答案是?

答案是:假真真假。

backward()

一个requires_grad为真的tensor可以backward(),而backward()就是根据计算图求梯度。所以我们可以查看a的梯度。即b对a的偏导,直觉上就是2。

a=torch.tensor([1.1],requires_grad=True)
b=a*2
print(b.requires_grad)
print(b)
b.backward()
print(a.grad)

Variable,Parameter和torch.tensor()

个人理解是:torch.tensor()、torch.autograd.Variable和torch.nn.Parameter 基本一样。

前两者都可以设置requires_grad参数,后者则直接默认requires_grad=True。

三者都拥有.data,.grad,.grad_fn等属性。

所以,只要requires_grad=True,都可以计算梯度以及backward()。

zero_grad()
a = torch.tensor([1.1], requires_grad=True)
b = a * 2
print(b)
c = b + 3
print(c)
b.backward(retain_graph=True)#计算图在backward一次之后默认就消失,我们下面还要backward一次,所以需要retain_graph=True保存这个图。
print(a.grad)
c.backward()
print(a.grad)


我们发现,b对a的梯度是2没有错,但是c对a的梯度是4,有错。这是因为没有对梯度进行清0,不清零的话,默认进行梯度叠加,Pytorch不设置自动清零,可能是叠加梯度有一些应用场景吧?所以我们需要手动清零。

a = torch.tensor([1.1], requires_grad=True)
b = a * 2
c = b + 3
b.backward(retain_graph=True)
print(a.grad)
a.grad.zero_()#tensor分为a.data和a.grad。这两个都是tensor。
#所以也可以a.grad=torch.tensor([0.0])
c.backward()
print(a.grad)

计算图

以上面这个代码为例,其计算图如下:

我们再来做一个实验,c对b的梯度是多少?很多人直接说1,但是在Pytorch中这个不允许计算。

a = torch.tensor([1.1], requires_grad=True)
b = a * 2
c = b + 3
c.backward()
print(a.grad)
print(b.grad)


而且还发出了警告提示信息:

UserWarning: The .grad attribute of a Tensor that is not a leaf Tensor is being accessed. Its .grad attribute won’t be populated during autograd.backward(). If you indeed want the gradient for a non-leaf Tensor, use .retain_grad() on the non-leaf Tensor. If you access the non-leaf Tensor by mistake, make sure you access the leaf Tensor instead. See github.com/pytorch/pytorch/pull/30531 for more information.

这是因为在Pytorch中不会对非叶子节点保存梯度,但是根据求导的链式法则,计算梯度肯定要。我们仔细观察上面那个计算图,只有如下是叶子节点

进一步,在Pytorch中只会对变量a求梯度,而2,3是常量。所以我们只得到了变量a的梯度。

拿神经网络举个例子给你,变量a就相当于神经网络中的参数(需要求梯度并且更新),那些常量就相当于你的输入,不要计算梯度,自然也不需要更新

with torch.no_grad()和backward()
a = torch.tensor([1.1], requires_grad=True)
b = a * 2
with torch.no_grad():
    c = b + 2
print(c.requires_grad)
d = torch.tensor([10.0], requires_grad=True)
e = c * d
print(e.requires_grad)
e.backward()
print(d.grad)
print(a.grad)


我们根据前面所学的知识,推导出前3个结果应该已经没有问题了,但是第4个怎么解释呢?很简单一句话,在计算图中,非叶子节点c作为“中间人”,如果其requires_grad=False,那么其前面的所有变量都无法反向传播,自然也就没有梯度,相当于卡住了。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/283400.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号