ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【PyTorch学习】二、自动求梯度(Automatic Gradient)

2022-01-17 19:06:04  阅读:200  来源: 互联网

标签:Gradient Automatic torch requires PyTorch True 梯度 print grad


PyTorch学习(二)


前言

torch.autograd是 PyTorch 的自动差分引擎,可为神经网络训练提供支持。

神经网络就是寻求一个拟合函数,但是因为参数过多,所以不得不借助每一点的梯度来一点一点的接近最佳的loss值,PyTorch 拥有动态的计算图,存储记忆对向量的每一个函数操作,最后通过反向传播来计算梯度,这可以说是pytorch的核心。

训练 神经网络 (Neural Network,NN)分为两个步骤:

正向传播:在正向传播中,NN 对正确的输出进行最佳猜测。 它通过其每个函数运行输入数据以进行猜测。

反向传播:在反向传播中,NN 根据其猜测中的误差调整其参数。 它通过从输出向后遍历,收集有关函数参数(梯度)的误差导数并使用梯度下降来优化参数来实现。


斯人若彩虹,遇上方知有。

一、autograd自动求梯度

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

深度学习模型的训练就是不断更新权值,权值的更新需要求解梯度。

Pytorch提供自动求导系统,我们不需要手动计算梯度,只需要搭建好前向传播的计算图,然后根据Pytorch中的autograd方法就可以得到所有张量的梯度。 PyTorch中,所有神经网络的核心是autograd包。autograd包为张量上的所有操作提供了自动求导机制。它是一个在运行时定义(define-by-run)的框架,这意味着反向传播是根据代码如何运行来决定的,并且每次迭代可以是不同的。

Variable和Tensor
Variable是 torch.autograd中的数据类型,主要用于封装 Tensor,进行自动求导。Pytorch 0.4.0版开始,Variable并入Tensor。

  • data : 被包装的Tensor
  • grad : data的梯度
  • grad_fn : 创建 Tensor的 Function,是自动求导的关键
  • requires_grad:指示是否需要梯度
  • is_leaf : 指示是否是叶子结点

Tensor是PyTorch实现多维数组计算和自动微分的关键数据结构。

  • dtype:张量的数据类型,如torch.FloatTensor,torch.cuda.FloatTensor
  • shape:张量的形状,如(64,3,224,224)
  • device:张量所在设备,GPU/CPU

Function类
Tensor和Function互相结合就可以构建一个记录有整个计算过程的有向无环图(Directed Acyclic Graph,DAG)。每个Tensor都有一个.grad_fn属性,该属性即创建该Tensor的Function。判断该Tensor是不是通过某些运算得到的,若是,则grad_fn返回一个与这些运算相关的对象,否则是None。

DAG的节点是Function对象,边表示数据依赖,从输出指向输入。 每当对Tensor施加一个运算的时候,就会产生一个Function对象,它产生运算的结果,记录运算的发生,并且记录运算的输入。Tensor使用.grad_fn属性记录这个计算图的入口。反向传播过程中,autograd引擎会按照逆序,通过Function的backward依次计算梯度。

自动求取梯度

torch.autograd.backward(tensors,
                    grad_tensors=None,
                    retain_grad=None,
                    create_graph=False)
  • tensors: 用于求导的张量,如loss
  • retain_graph : 保存计算图;由于pytorch采用动态图机制,在每一次反向传播结束之后,计算图都会释放掉。如果想继续使用计算图,就需要设置参数retain_graph为True
  • create_graph : 创建导数计算图,用于高阶求导,例如二阶导数、三阶导数等
  • grad_tensors:多梯度权重;当有多个loss需要去计算梯度的时候,就要设计各个loss之间的权重比例

计算并返回outputs对inputs的梯度

torch.autograd.grad(outputs,
                inputs,
                grad_outputs=None,
                retain_graph=None,
                create_graph=False)
  • outputs:用于求导的张量,如loss
  • inputs:需要梯度的张量,如w
  • create_graph:创建导数计算图,用于高阶求导
  • retain_graph:保存计算图
  • grad_outputs:多梯度权重

注意事项

(1)梯度不自动清零,如果不清零梯度会累加,所以需要在每次梯度后人为清零。
(2)依赖于叶子结点的结点,requires_grad默认为True。
(3)叶子结点不可执行in-place,因为其他节点在计算梯度时需要用到叶子节点,所以叶子地址中的值不得改变否则会是其他节点求梯度时出错。所以叶子节点不能进行原位计算。
(4)注意在y.backward()时,如果y是标量量,则不需要为backward()传⼊入任何参数;否则,需要传⼊一个与y同形的Tensor。

二、使用步骤

1.示例一

from torch.autograd import Variable, Function
import torch

# 生成Variable
x = Variable(torch.ones(2, 2), requires_grad=True) # requires_grad表示在backward是否计算其梯度
print(x)

print('-----------------------')

# 查看Variable的属性.data, .grad, .creator
print(x.data)    # Variable保存的值
print(x.grad)    # 由于目前还未进行.backward()运算,因此不存在梯度
# print(x.creator)  # 对于手动申明的Variable,不存在creator,即在计算图中,该Variable不存在父节点
# creator属性名称已经改为grad_fn
print(x.grad_fn)  # 可获取y的已创建Function属性的属性Variable

print('-----------------------')

# Variable进行运算
y = x + 2
print(y)
# print(y.creator) # y存在x这个父节点,并且通过'+'这个Function进行连接,因此y.creator是运算+
print(x.grad_fn)

2.示例二

import torch

#创建一个`Tensor`并设置`requires_grad=True`
x = torch.ones(2, 2, requires_grad=True)
print(x)
print(x.grad_fn)  # None

# 再做一下运算操作:
y = x + 2
print(y)  # grad_fn=<AddBackward0>
print(y.grad_fn)

#像x这种直接创建的称为叶子节点,叶子节点对应的`grad_fn`是`None`。
print(x.is_leaf, y.is_leaf) # True False

#再来点复杂度运算操作:
z = y * y * 3  # 27
out = z.mean()
print(z, out)  # grad_fn=<MulBackward0>

#通过`.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)


torch.manual_seed(10)  #用于设置随机数
w = torch.tensor([1.], requires_grad=True)    #创建叶子张量,并设定requires_grad为True,因为需要计算梯度;
x = torch.tensor([2.], requires_grad=True)    #创建叶子张量,并设定requires_grad为True,因为需要计算梯度;
a = torch.add(w, x)    #执行运算并搭建动态计算图
b = torch.add(w, 1)
y = torch.mul(a, b)
y.backward(retain_graph=True)
print(w.grad)   #输出为tensor([5.])


x = torch.tensor([1.0, 2.0, 3.0, 4.0], requires_grad=True)
y = 2 * x
z = y.view(2, 2)
print(z)

#现在 `z` 不是一个标量,所以在调用`backward`时需要传入一个和`z`同形的权重向量进行加权求和得到一个标量。
v = torch.tensor([[1.0, 0.1], [0.01, 0.001]], dtype=torch.float)
z.backward(v)
print(x.grad)

#再来看看中断梯度追踪的例子:
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

#可以看到,上面的`y2`是没有`grad_fn`而且`y2.requires_grad=False`的,而`y3`是有`grad_fn`的。如果我们将`y3`对`x`求梯度的话会是多少呢?
y3.backward()
print(x.grad)

#此外,如果我们想要修改`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)

标签:Gradient,Automatic,torch,requires,PyTorch,True,梯度,print,grad
来源: https://blog.csdn.net/weixin_43182102/article/details/122420904

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有