PyTorch提供的autograd包能够根据输⼊和前向传播过程⾃动构建计算图,并执⾏反向传播。

Tensor

Tensor的几个重要属性或方法

  • .requires_grad 设为true的话,tensor将开始追踪在其上的所有操作
  • .backward()完成梯度计算
  • .grad属性 计算的梯度累积到.grad属性
  • .detach()解除对一个tensor上操作的追踪,或者用with torch.no_grad()将不想被追踪的操作代码块包裹起来.
  • .grad_fn属性 该属性即创建Tensor的Function类的类型,即该Tensor是由什么运算得来的

几个例子具体地解释一下:

import torch
x = torch.ones(2, 2, requires_grad=True)
print(x)
print(x.grad_fn) y = x+2
print(y)
print(y.grad_fn) z = y*y*3
out=z.mean()
print(z,out)

输出

tensor([[1., 1.],
[1., 1.]], requires_grad=True)
None
tensor([[3., 3.],
[3., 3.]], grad_fn=<AddBackward>)
<AddBackward object at 0x0000018752434B70> tensor([[27., 27.],
[27., 27.]], grad_fn=<MulBackward>) tensor(27., grad_fn=<MeanBackward1>)

y由加法得到,所以y.grad_fn=,x直接创建,其x.grad_fn=None. x这种直接创建的又称为叶子节点.

print(x.is_leaf, y.is_leaf) # True False

可以用.requires_grad_()来用in-place的方式改变requires_grad属性.

a = torch.randn(2, 2) # 缺失情况下默认 requires_grad = False
a = ((a * 3) / (a - 1))
print(a.requires_grad) # False
a.requires_grad_(True)
print(a.requires_grad) # True
b = (a * a).sum()
print(b.grad_fn)

输出

False
True
<SumBackward0 object at 0x0000018752434D30>

梯度

所计算的梯度都是结果变量关于创建变量的梯度。

比如对:

x = torch.ones(2, 2, requires_grad=True)
print(x)
print(x.grad_fn) y = x+2
print(y)
print(y.grad_fn) z = y*3
z.backward(torch.ones_like(z))
print(y.grad) #None
print(x.grad)

输出

None
tensor([[3., 3.],
[3., 3.]])

上述代码相当于创建了一个动态图,其中x是我们创建的变量,y和z都是因为x的改变会改变的结果变量. 所以在这个动态图里能够求的梯度只有\(\frac{\partial{z}}{\partial{x}}\),\(\frac{\partial{y}}{\partial{x}}\)

为什么l.backward(gradient)需要传入一个和l同样形状的gradient?

对于l.backward()而言,当l是标量时,可以不传参,相当于l.backward(torch.tensor(1.))

当l不是标量时,需要传入一个和l同shape的gradient。

假设 x 经过一番计算得到 y,那么 y.backward(w) 求的不是 y 对 x 的导数,而是 l = torch.sum(y*w) 对 x 的导数。w 可以视为 y 的各分量的权重,也可以视为遥远的损失函数 l 对 y 的偏导数(这正是函数说明文档的含义)。特别地,若 y 为标量,w 取默认值 1.0,才是按照我们通常理解的那样,求 y 对 x 的导数

简单地说就是,张量对张量没法求导,所以我们需要人为地定义一个w,把一个非标量的Tensor通过torch.sum(y*w)的形式转换成标量。我们自己定义的这个w的不同,当然最后得到的梯度就不同.通常定义为全1.也就是认为Tensor y中的每一个变量的重要性是等同的.

另一个角度的理解就是,y是一个tensor,是一个向量,有N个标量,这每一个标量都与x有关。对这N个标量我们需要赋以不同的权重,以显示y中每一个标量受到x影响的程度.

比如对

import torch
x = torch.ones(2, 2, requires_grad=True)
print(x)
print(x.grad_fn) y = x+2
print(y)
print(y.grad_fn) z = y*3
print(z.shape)
w1=torch.Tensor([[1,2],[1,2]])
z.backward([w1])
print(x.grad) x.grad.data.zero_()
w2=torch.Tensor([[1,1],[1,1]])
z.backward([w2])
print(x.grad)

输出

tensor([[1., 1.],
[1., 1.]], requires_grad=True)
None
tensor([[3., 3.],
[3., 3.]], grad_fn=<AddBackward>)
<AddBackward object at 0x00000187524A6828>
torch.Size([2, 2])
tensor([[3., 6.],
[3., 6.]])
tensor([[3., 3.],
[3., 3.]])

对w1和w2而言,z.backward()以后x.grad是不同的。

注意:梯度是累加的,所以第二次计算之前我们做了清零的操作:x.grad.data.zero_()

可以参考:

https://zhuanlan.zhihu.com/p/29923090

https://www.cnblogs.com/zhouyang209117/p/11023160.html

再来看看中断梯度追踪的例子:

x = torch.tensor(1.0, requires_grad=True)
y1 = x ** 2
with torch.no_grad():
y2 = x ** 3
y3 = y1 + y2 print(x.requires_grad)
print(y1, y1.requires_grad) # True
print(y2, y2.requires_grad) # False
print(y3, y3.requires_grad) # True

输出:

True
tensor(1., grad_fn=<PowBackward0>) True
tensor(1.) False
tensor(2., grad_fn=<ThAddBackward>) True

反向传播,求梯度

y3.backward()
print(x.grad)

输出:

tensor(2.)

为什么是2呢?$ y_3 = y_1 + y_2 = x^2 + x^3$,当 \(x=1\) 时 \(\frac {dy_3} {dx}\) 不应该是5吗?事实上,由于 \(y_2\) 的定义是被torch.no_grad():包裹的,所以与 \(y_2\) 有关的梯度是不会回传的,只有与 \(y_1\) 有关的梯度才会回传,即 \(x^2\) 对 \(x\) 的梯度。

上面提到,y2.requires_grad=False,所以不能调用 y2.backward(),会报错:

RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn

此外,如果我们想要修改tensor的数值,但是又不希望被autograd记录(即不会影响反向传播),那么我么可以对tensor.data进行操作。

x = torch.ones(1,requires_grad=True)

print(x.data) # 还是一个tensor
print(x.data.requires_grad) # 但是已经是独立于计算图之外 y = 2 * x
x.data *= 100 # 只改变了值,不会记录在计算图,所以不会影响梯度传播 y.backward()
print(x) # 更改data的值也会影响tensor的值
print(x.grad)

输出:

tensor([1.])
False
tensor([100.], requires_grad=True)
tensor([2.])

从头学pytorch(二) 自动求梯度的更多相关文章

  1. 从头学pytorch(二十):残差网络resnet

    残差网络ResNet resnet是何凯明大神在2015年提出的.并且获得了当年的ImageNet比赛的冠军. 残差网络具有里程碑的意义,为以后的网络设计提出了一个新的思路. googlenet的思路 ...

  2. 从头学pytorch(二十二):全连接网络dense net

    DenseNet 论文传送门,这篇论文是CVPR 2017的最佳论文. resnet一文里说了,resnet是具有里程碑意义的.densenet就是受resnet的启发提出的模型. resnet中是把 ...

  3. PyTorch入门学习(二):Autogard之自动求梯度

    autograd包是PyTorch中神经网络的核心部分,简单学习一下. autograd提供了所有张量操作的自动求微分功能. 它的灵活性体现在可以通过代码的运行来决定反向传播的过程, 这样就使得每一次 ...

  4. pytorch 自动求梯度

    自动求梯度 在深度学习中,我们经常需要对函数求梯度(gradient).PyTorch提供的autograd包能够根据输入和前向传播过程自动构建计算图,并执行反向传播.本节将介绍如何使用autogra ...

  5. Pytorch中的自动求梯度机制和Variable类

    自动求导机制是每一个深度学习框架中重要的性质,免去了手动计算导数,下面用代码介绍并举例说明Pytorch的自动求导机制. 首先介绍Variable,Variable是对Tensor的一个封装,操作和T ...

  6. 从头学pytorch(三) 线性回归

    关于什么是线性回归,不多做介绍了.可以参考我以前的博客https://www.cnblogs.com/sdu20112013/p/10186516.html 实现线性回归 分为以下几个部分: 生成数据 ...

  7. Pytorch Autograd (自动求导机制)

    Pytorch Autograd (自动求导机制) Introduce Pytorch Autograd库 (自动求导机制) 是训练神经网络时,反向误差传播(BP)算法的核心. 本文通过logisti ...

  8. 从头学pytorch(一):数据操作

    跟着Dive-into-DL-PyTorch.pdf从头开始学pytorch,夯实基础. Tensor创建 创建未初始化的tensor import torch x = torch.empty(5,3 ...

  9. pytorch的自动求导机制 - 计算图的建立

    一.计算图简介 在pytorch的官网上,可以看到一个简单的计算图示意图, 如下. import torchfrom torch.autograd import Variable x = Variab ...

随机推荐

  1. SSM配置梳理

      这两天梳理了一下 SSM 的配置,做一个小总结   可能有一些不对的地方,如果您发现了什么错误,非常希望能帮忙指出,谢谢 我参考了很多文章,都标明了来源(链接),可能会影响阅读的连贯性,抱歉   ...

  2. kubernetes实战(二十八):Kubernetes一键式资源管理平台Ratel安装及使用

    1. Ratel是什么? Ratel是一个Kubernetes资源平台,基于管理Kubernetes的资源开发,可以管理Kubernetes的Deployment.DaemonSet.Stateful ...

  3. SqlServer2005 查询 第一讲 计算列

    数据库查询[最重要且在数据库中难度最大] 声明一下我这里用的数据库样例是郝斌老师的(scott库) 我尽最大努力把复杂的问题简单化,方便理解,希望我写的东西能够帮助到你们 有些复杂的东西我我用自己的方 ...

  4. H5 - css3(学习c3的第一天)

    css3 中的转换:可以对元素进行移动.缩放.装懂.拉长或拉伸. 属性值:transform 每个浏览器的内核都不同,所以对应的前缀也不同,谷歌的是:  -webkit-  :  ie的是  -ms- ...

  5. Vue导入非模块化的第三方插件功能无效解决方案

    一.问题: 最近在写vue项目时,想引入某些非模块化的第三方插件时,总是发现会有报错.且在与本地运行插件测试对比时发现插件根本没有注入到jQuery中(console.log($.fn)查看当前jq有 ...

  6. Vue注册组件命名时不能用大写的原因浅析

    命名使用注意事项: https://www.jb51.net/article/160227.htm

  7. PostGIS安装教程

    安装环境: win10专业版 postgresql-10.6-1-windows-x64 ---因为使用的是ArcGIS10.4版本,pg10.6对于ArcGIS10.4版本过高,建议选择安装pg9. ...

  8. 基于Galera Cluster多主结构的Mysql高可用集群

    Galera Cluster特点 1.多主架构:真正的多点读写的集群,在任何时候读写数据,都是最新的 2.同步复制:集群不同节点之间数据同步,没有延迟,在数据库挂掉之后,数据不会丢失 3.并发复制:从 ...

  9. Relation-Shape Convolutional Neural Network for Point Cloud Analysis(CVPR 2019)

    代码:https://github.com/Yochengliu/Relation-Shape-CNN 文章:https://arxiv.org/abs/1904.07601 作者直播:https:/ ...

  10. 【集训Day1 测试】装饰

    装饰(decorate) [题目描述] 一个图有 N 个结点,编号 1 至 N,有 M 条无向边,第 i 条边连接的两个结点是 Ai 和Bi,其中 Ai 和 Bi 是不同的结点.可能有多条边连接的是同 ...