东方耀AI技术分享

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
热搜: 活动 交友 discuz
查看: 5626|回复: 11
打印 上一主题 下一主题

[PyTorch] 02、Autograd: 自动求导机制

[复制链接]

1365

主题

1856

帖子

1万

积分

管理员

Rank: 10Rank: 10Rank: 10

积分
14435
QQ
跳转到指定楼层
楼主
发表于 2020-4-9 16:36:19 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
Autograd: 自动求导机制
PyTorch 中所有神经网络的核心是 autograd 包。 我们先简单介绍一下这个包,然后训练第一个简单的神经网络。


autograd包为张量上的所有操作提供了自动求导。 它是一个在运行时定义的框架,这意味着反向传播是根据你的代码来确定如何运行,并且每次迭代可以是不同的。




张量Tensor
torch.Tensor是这个包的核心类。如果设置 .requires_grad 为 True,那么将会追踪所有对于该张量的操作。 当完成计算后通过调用 .backward(),自动计算所有的梯度, 这个张量的所有梯度将会自动积累到 .grad 属性。


要阻止张量跟踪历史记录,可以调用.detach()方法将其与计算历史记录分离,并禁止跟踪它将来的计算记录。


为了防止跟踪历史记录(和使用内存),可以将代码块包装在with torch.no_grad():中。 在评估模型时特别有用,因为模型可能具有requires_grad = True的可训练参数,但是我们不需要梯度计算。


在自动梯度计算中还有另外一个重要的类Function.


Tensor and Function are interconnected and build up an acyclic graph, that encodes a complete history of computation. Each tensor has a .grad_fn attribute that references a Function that has created the Tensor (except for Tensors created by the user - their grad_fn is None).


Tensor 和 Function互相连接并生成一个非循环图,它表示和存储了完整的计算历史。 每个张量都有一个.grad_fn属性,这个属性引用了一个创建了Tensor的Function(除非这个张量是用户手动创建的,即,这个张量的 grad_fn 是 None)。


如果需要计算导数,你可以在Tensor上调用.backward()。 如果Tensor是一个标量(即它包含一个元素数据)则不需要为backward()指定任何参数, 但是如果它有更多的元素,你需要指定一个gradient 参数来匹配张量的形状。




创建一个张量并设置 requires_grad=True 用来追踪他的计算历史
x = torch.ones(2, 2, requires_grad=True)


.requires_grad_( ... ) 可以改变现有张量的 requires_grad属性。 如果没有指定的话,默认输入的flag是 False




a = torch.randn(2, 2)
a = ((a * 3) / (a - 1))
print(a.requires_grad)
a.requires_grad_(True)
print(a.requires_grad)
b = (a * a).sum()
print(b.grad_fn)


如果.requires_grad=True但是你又不希望进行autograd的计算, 那么可以将变量包裹在 with torch.no_grad()中








让天下人人学会人工智能!人工智能的前景一片大好!
回复

使用道具 举报

1365

主题

1856

帖子

1万

积分

管理员

Rank: 10Rank: 10Rank: 10

积分
14435
QQ
沙发
 楼主| 发表于 2020-4-10 10:03:17 | 只看该作者
从0.4起, Variable 正式合并入Tensor类, 通过Variable嵌套实现的自动微分功能已经整合进入了Tensor类中。虽然为了代码的兼容性还是可以使用Variable(tensor)这种方式进行嵌套, 但是这个操作其实什么都没做。

所以,以后的代码建议直接使用Tensor类进行操作,因为官方文档中已经将Variable设置成过期模块。

要想通过Tensor类本身就支持了使用autograd功能,只需要设置.requries_grad=True

Variable类中的的grad和grad_fn属性已经整合进入了Tensor类中
让天下人人学会人工智能!人工智能的前景一片大好!
回复

使用道具 举报

1365

主题

1856

帖子

1万

积分

管理员

Rank: 10Rank: 10Rank: 10

积分
14435
QQ
板凳
 楼主| 发表于 2020-4-10 10:04:28 | 只看该作者
在张量创建时,通过设置 requires_grad 标识为Ture来告诉Pytorch需要对该张量进行自动求导,PyTorch会记录该张量的每一步操作历史并自动计算
让天下人人学会人工智能!人工智能的前景一片大好!
回复

使用道具 举报

1365

主题

1856

帖子

1万

积分

管理员

Rank: 10Rank: 10Rank: 10

积分
14435
QQ
地板
 楼主| 发表于 2020-4-10 10:07:26 | 只看该作者
在张量进行操作后,grad_fn已经被赋予了一个新的函数,这个函数引用了一个创建了这个Tensor类的Function对象。
Tensor和Function互相连接生成了一个非循环图,它记录并且编码了完整的计算历史。每个张量都有一个.grad_fn属性,如果这个张量是用户手动创建的那么这个张量的grad_fn是None。
让天下人人学会人工智能!人工智能的前景一片大好!
回复

使用道具 举报

1365

主题

1856

帖子

1万

积分

管理员

Rank: 10Rank: 10Rank: 10

积分
14435
QQ
5#
 楼主| 发表于 2020-4-10 10:15:12 | 只看该作者
自动求导
如果Tensor类表示的是一个标量(即它包含一个元素的张量),则不需要为backward()指定任何参数,但是如果它有更多的元素,则需要指定一个gradient参数,它是形状匹配的张量。
以上的 z.backward()相当于是z.backward(torch.tensor(1.))的简写。 这种参数常出现在图像分类中的单标签分类,输出一个标量代表图像的标签

#我们的返回值不是一个标量,所以需要输入一个大小相同的张量作为参数,这里我们用ones_like函数根据x生成一个张量
z.backward(torch.ones_like(x))
print(x.grad)
让天下人人学会人工智能!人工智能的前景一片大好!
回复

使用道具 举报

1365

主题

1856

帖子

1万

积分

管理员

Rank: 10Rank: 10Rank: 10

积分
14435
QQ
6#
 楼主| 发表于 2020-4-10 10:22:02 | 只看该作者
为了说明Pytorch的自动求导原理,我们来尝试分析一下PyTorch的源代码,虽然Pytorch的 Tensor和 TensorBase都是使用CPP来实现的,
但是可以使用一些Python的一些方法查看这些对象在Python的属性和状态。 Python的 dir() 返回参数的属性、方法列表。z是一个Tensor变量,看看里面有哪些成员变量。 dir(z)


返回很多,我们直接排除掉一些Python中特殊方法(以__开头和结束的)和私有方法(以_开头的,直接看几个比较主要的属性: .is_leaf:记录是否是叶子节点。
通过这个属性来确定这个变量的类型 在官方文档中所说的“graph leaves”,“leaf variables”,都是指像x,y这样的手动创建的、而非运算得到的变量,这些变量成为创建变量。
像z这样的,是通过计算后得到的结果称为结果变量。

一个变量是创建变量还是结果变量是通过.is_leaf来获取的
让天下人人学会人工智能!人工智能的前景一片大好!
回复

使用道具 举报

1365

主题

1856

帖子

1万

积分

管理员

Rank: 10Rank: 10Rank: 10

积分
14435
QQ
7#
 楼主| 发表于 2020-4-10 10:27:19 | 只看该作者
next_functions就是grad_fn的精华
z.grad_fn.next_functions
让天下人人学会人工智能!人工智能的前景一片大好!
回复

使用道具 举报

1365

主题

1856

帖子

1万

积分

管理员

Rank: 10Rank: 10Rank: 10

积分
14435
QQ
8#
 楼主| 发表于 2020-4-10 10:27:27 | 只看该作者
这样整个规程就很清晰了:

当我们执行z.backward()的时候。这个操作将调用z里面的grad_fn这个属性,执行求导的操作。
这个操作将遍历grad_fn的next_functions,然后分别取出里面的Function(AccumulateGrad),执行求导操作。这部分是一个递归的过程直到最后类型为叶子节点。
计算出结果以后,将结果保存到他们对应的variable 这个变量所引用的对象(x和y)的 grad这个属性里面。
求导结束。所有的叶节点的grad变量都得到了相应的更新
最终当我们执行完c.backward()之后,a和b里面的grad值就得到了更新。
让天下人人学会人工智能!人工智能的前景一片大好!
回复

使用道具 举报

0

主题

13

帖子

54

积分

2W人工智能培训

Rank: 10Rank: 10Rank: 10

积分
54
9#
发表于 2020-6-15 22:08:14 | 只看该作者
有pytorch视频教程吗
回复

使用道具 举报

0

主题

19

帖子

42

积分

新手上路

Rank: 1

积分
42
10#
发表于 2021-11-1 14:21:55 | 只看该作者
ice_spring 发表于 2020-6-15 22:08
有pytorch视频教程吗

为了达到198为了达到198为了达到198为了达到198为了达到198为了达到198
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|人工智能工程师的摇篮 ( 湘ICP备2020019608号-1 )

GMT+8, 2024-4-29 21:46 , Processed in 0.184891 second(s), 18 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表