在训练神经网络时,最常用的算法是反向传播。PyTorch的反向传播(即tensor.backward())是通过autograd包来实现的,autograd包会根据tensor进行过的数学运算来自动计算其对应的梯度。在该算法中,参数(模型权重)根据损失函数相对于给定参数的梯度进行调整。为了计算这些梯度,Pytorch有一个名为 torch.autograd 的内置微分引擎。它支持自动计算任何计算图形的梯度。本例中考虑最简单的单层神经网络,输入x,参数w和b,以及一些损失函数。可通过以下方式在PyTorch中定义:

import torchx = torch.ones(5)  # input tensor,返回一个全为1 的张量,形状由可变参数sizes定义
y = torch.zeros(3)  # expected output,返回一个全为标量 0 的张量
w = torch.randn(5, 3, requires_grad=True)#返回一个符合均值为0,方差为1的正态分布(标准正态分布)中填充随机数的张量
b = torch.randn(3, requires_grad=True)  #requires_grad(bool, optional) –autograd是否应该记录对返回张量的操作(说明当前量是否需要在计算中保留对应的梯度信息)。
z = torch.matmul(x, w)+b#两个张量矩阵x,w相乘
loss = torch.nn.functional.binary_cross_entropy_with_logits(z, y)#对神经网络的输出结果进行sigmoid操作,然后求交叉熵

其中torch.randn()函数返回一个符合标准正态分布填充随机数的张量参数requires_grad的含义是如果需要为张量计算梯度,则为True,否则为False。在使用pytorch创建tensor时,可以指定requires_grad为True(默认为False),更多含义参考:

torch.randn()函数_meteor,across T sky的博客-CSDN博客_torch.randn()

其中torch.matmul(input, other) 函数是计算两个张量input和other的矩阵乘积。因为matmul函数没有强制规定维度和大小,可以用利用广播机制进行不同维度的相乘操作。本例中input为一维,other为二维,则先将input的一维向量扩充到二维,然后进行矩阵乘积,得到结果后再将此维度去掉,得到的与input的维度相同。该函数的多维张量操作详见:

PyTorch疑难杂症(1)——torch.matmul()函数用法总结_wendy_ya的博客-CSDN_torch.matmul

其中torch.nn.functional.binary_cross_entropy_with_logits函数的功能是先对神经网络的输出结果进行Sigmoid激活操作,然后求交叉熵。作用是衡量真实分布和预测的分布的差异情况。参数input神经网络的预测结果(未经过sigmoid),任意形状的tensor。参数target是标签值,与input形状相同。详细的参数如下:

pytorch常用函数:torch.nn.functional.binary_cross_entropy_with_logits_xingS1992的博客-CSDN博客_torch.nn.functional.binary_cross_entropy

1、张量、函数和计算图

以上代码可以定义以下计算图

(1)在这个网络中,w和b是需要优化的参数。 因此就要计算损失函数相对于这些变量的梯度变化。 为了做到这一点,设置了requires_grad方法查看这些张量的属性。该方法的作用是,如果需要为张量计算梯度,则为True,否则为False。(你可以在创建张量时设置requires_grad的值,或稍后使用x.requires_grad(True)方法设置。)例如:

a = torch.randn(2, 2) # 缺失情况下默认 requires_grad = False
x = ((a * 5) / (a - 5))
print(x.requires_grad) # False
a.requires_grad_(True)
print(a.requires_grad) # True

(2)接下来用张量来构造计算图的函数,该函数实际上是类函数的对象。 该对象知道如何计算正向传播的函数,以及如何在反向传播步骤中计算其导数。grad_fn方法用来记录变量是怎么来的,方便计算梯度,例如y = x*3,grad_fn记录了y由x计算的过程。

print(f"Gradient function for z = {z.grad_fn}")
print(f"Gradient function for loss = {loss.grad_fn}")
print(x.grad_fn)

由于x是直接创建的,所以它没有grad_fn,而z是通过计算创建的,所以z有grad_fn。像x这种直接创建的称为叶子节点,叶子节点对应的grad_fn是None。如果需要在同一个图上执行多个backward调用,需要将retain_graph=True传递给backward调用。输出结果:

Gradient function for z = <AddBackward0 object at 0x000001F22FED1AF0>
Gradient function for loss = <BinaryCrossEntropyWithLogitsBackward0 object at 0x000001F22FED1AF0>
None

2、计算梯度

为了优化神经网络中参数的权重,就需要计算损失函数对参数的导数,即需要求得x和y在某些固定值下的导数。为了计算这些导数,我们调用loss.backward()函数,然后从w.grad和b.grad中检索梯度值:

loss.backward()
print(w.grad)
print(b.grad)

其中grad方法是当执行完了backward()之后,通过x.grad查看w和b的梯度值。另外grad在反向传播过程中是累加的,这意味着每一次运行反向传播,梯度都会累加之前的梯度,所以一般在反向传播之前需把梯度清零。如果不将梯度清零的话,梯度会与上一个batch的数据相关。但是如果没有进行tensor.backward()的话,梯度值将会是None。

tensor([[0.0981, 0.2268, 0.2431],[0.0981, 0.2268, 0.2431],[0.0981, 0.2268, 0.2431],[0.0981, 0.2268, 0.2431],[0.0981, 0.2268, 0.2431]])
tensor([0.0981, 0.2268, 0.2431])

总结:如果设置tensor的requires_grads为True,那么就会开始跟踪这个tensor上面的所有运算,则w的所有上层参数(后面层的权重w)的w.grad_fn属性中就保存了对应的运算,如果做完运算后使用tensor.backward(),所有的梯度就会自动运算,会一层层的反向传播计算每个w的梯度值,tensor的梯度将会累加到 w.grad 属性里面去。 下面是计算梯度时用到的三种方法 requires_grad,grad_fn,grad的含义及使用:

requires_grad,grad_fn,grad的含义及使用_dlage的博客-CSDN博客_requires_grad_

3、梯度跟踪禁用

默认情况下,所有requires_grad=True的张量跟踪它们的计算历史并支持梯度计算。但是也有一些情况不需要这样做,比如已经训练好了模型,只是想把它应用到一些输入数据上,只是想通过网络进行正向计算。这时可以通过使用torch.no_grad()块包围计算代码来停止跟踪计算:

z = torch.matmul(x, w)+b
print(z.requires_grad) #True
with torch.no_grad():z = torch.matmul(x, w)+b
print(z.requires_grad) #False

实现相同结果的另一种方法是在张量上使用 detach()方法 :

z = torch.matmul(x, w)+b
z_det = z.detach()
print(z_det.requires_grad) #False

禁用梯度跟踪的原因有:把神经网络中的一些参数标记为冻结参数。这是对预训练网络进行微调的一个非常常见的场景。另外当只做前向传递时,可以加速计算,因为不跟踪梯度的张量的计算会更有效率。

4、AUTOGRAD 自动微分总结

从概念上讲,autograd在一个由Function对象组成的有向无环图(DAG)中保存数据(张量)和所有执行的操作(以及生成的新张量)的记录。在这个DAG中,叶是输入张量,根是输出张量。通过跟踪这个从根到叶的图,使用链式法则自动计算梯度。
(1)在前向传递中,autograd同时做两件事:运行请求的操作来计算结果张量。在DAG中维护操作的梯度函数。

(2)当在DAG根节点上调用.backward()时,后向传递开始。autograd计算每个  .grad_fn的梯度。将它们累积到各自张量的  .grad属性中。利用链式法则,一直传播到叶张量。

另外,计算图是从头再创建的,在每次 .backward()调用之后,autograd开始填充一个新图。这正是可以让我们在模型中使用控制流语句的原因,如果需要,可以在每次迭代中更改形状、大小和操作。

5、张量梯度和雅可比积

在很多情况下,我们有一个标量损失函数,我们需要计算一些参数的梯度。然而,在某些情况下,输出函数是任意张量。在这种情况下,PyTorch允许我们计算所谓的雅可比积,而不是实际的梯度。

对于向量函数,其中相对于的梯度由雅可比矩阵给出:

并不是计算雅可比矩阵本身,PyTorch允许计算雅可比矩阵积vT⋅ 对于J给定的输入向量v=(v1…vm)。这是通过将v作为参数调用 backward 来实现的。v的大小应该和原始张量的大小一样,我们要根据原始张量计算乘积:

inp = torch.eye(5, requires_grad=True)#生成对角线全1,其余部分全0的二维数组
out = (inp+1).pow(2)#计算数的次方
out.backward(torch.ones_like(inp), retain_graph=True)#根据给定张量,生成与其形状相同的全1张量
print(f"First call\n{inp.grad}")
out.backward(torch.ones_like(inp), retain_graph=True)
print(f"\nSecond call\n{inp.grad}")
inp.grad.zero_()#将模型参数的梯度置为0
out.backward(torch.ones_like(inp), retain_graph=True)
print(f"\nCall after zeroing gradients\n{inp.grad}")

其中retain_graph=True代表可以再来一次backward。如果设置为False,计算图中的中间变量在计算完后就会被释放清除。这样进行第二次backward会报错。但是在平时的使用中这个参数默认都为False从而提高效率。

tensor([[4., 2., 2., 2., 2.],[2., 4., 2., 2., 2.],[2., 2., 4., 2., 2.],[2., 2., 2., 4., 2.],[2., 2., 2., 2., 4.]])Second call
tensor([[8., 4., 4., 4., 4.],[4., 8., 4., 4., 4.],[4., 4., 8., 4., 4.],[4., 4., 4., 8., 4.],[4., 4., 4., 4., 8.]])Call after zeroing gradients
tensor([[4., 2., 2., 2., 2.],[2., 4., 2., 2., 2.],[2., 2., 4., 2., 2.],[2., 2., 2., 4., 2.],[2., 2., 2., 2., 4.]])

当使用相同的参数第二次backward调用时,梯度的值是不同的。这是因为当进行逆向传播时,PyTorch会累积梯度,即计算的梯度值会被添加到计算图所有叶节点的梯度属性中。如果想要计算适当的梯度,需要在之前将梯度属性归零。在现实训练中,优化器可以帮助我们做到这一点。之前调用的是没有参数的backward()函数。这本质上相当于调用backward(torch.tensor(1.0)),这也是计算标量值函数(比如神经网络训练期间的损失)的梯度的一种有用方法。

pytorch基础-使用 TORCH.AUTOGRAD 进行自动微分(5)相关推荐

  1. Pytorch基础(二) 初始自动微分

    torch.tensor是包的核心类,若将其属性.requires_grad设置为True,则会开始跟踪tensor的所有操作,完成计算后,可以调用.backward()来自动计算所有梯度.该张量的梯 ...

  2. PyTorch深度学习基础之Reduction归约和自动微分操作讲解及实战(附源码 超详细必看)

    创作不易 觉得有帮助请点赞关注收藏~~~ 一.PyTorch的Reduction操作 Reduction运算的特点是它往往对一个Tensor内的元素做归约操作,比如torch.max找极大值,torc ...

  3. 【PyTorch】1入门——Tensor、自动微分、神经网络、PyTorch 图像分类

    PyTorch60min入门教程 1. PyTorch简介 2. 快速入门 2.1 安装与配置 2.2 PyTorch入门第一步 2.2.1 Tensor 2.2.2 自动微分 2.2.3 神经网络 ...

  4. pytorch基础知识整理(一)自动求导机制

    torch.autograd torch.autograd是pytorch最重要的组件,主要包括Variable类和Function类,Variable用来封装Tensor,是计算图上的节点,Func ...

  5. 【翻译】Extending PyTorch之Extending torch.autograd和Extending torch.nn

    原文链接: Extending PyTorch 参考链接: Difference between apply an call for an autograd function Extending Py ...

  6. 3.Pytorch基础模块torch的API之Indexing,Slicing,Joining,Mutating Ops实例详解

    文章目录 0. torch 1. Tensors 2. Creation Ops 3. Indexing,Slicing,Joining,Mutating Ops 3.1 torch.cat() 3. ...

  7. 深度学习利器之自动微分(2)

    深度学习利器之自动微分(2) 文章目录 深度学习利器之自动微分(2) 0x00 摘要 0x01 前情回顾 0x02 自动微分 2.1 分解计算 2.2 计算模式 2.3 样例 2.4 前向模式(For ...

  8. 《深度学习之pytorch实战计算机视觉》第6章 PyTorch基础(代码可跑通)

    上一篇文章<深度学习之pytorch实战计算机视觉>第5章 Python基础讲了Python基础.接下来看看第6章 PyTorch基础. 目录 6.1 PyTorch中的Tensor 6. ...

  9. 自动微分到底是什么?这里有一份自我简述

    机器之心整理 参与:思.Jamin 一直以来,自动微分都在 DL 框架背后默默地运行着,本文希望探讨它到底是什么,通过 JAX,自动微分又能怎么用. 自动微分现在已经是深度学习框架的标配,我们写的任何 ...

最新文章

  1. 内存与mysql_MySQL的内存和相关问题排查
  2. 在django中区分null = True,空白= True
  3. 鸿蒙2.0升级计划名单,鸿蒙OS 2.0适配 计划-升级名单
  4. 微软职位内部推荐-Senior Development Lead – Sharepoint
  5. 检索 COM 类工厂中 CLSID 为 { } 的组件时失败,原因是呈现以下错误: 80040154
  6. 【学习笔记】Miller-Rabin(米勒-拉宾)素性测试,附常用表
  7. c++虚函数和虚函数表
  8. 54.购物流程(1)---simple product
  9. 笔记3:STM32F103与STM32F030的区别
  10. Spark编程基础-(一)大数据技术概述
  11. 小米pro15拆机_实战小米笔记本PRO 15.6寸拆解 加装M.2海力士固态硬盘
  12. 【前端进阶】-TypeScript类型声明文件详解及使用说明
  13. 移动互联网创业者遭遇巨头模仿蚕食
  14. Java根据纯真IP库获取具体的地址信息
  15. 万亿候苹果,1000000000000 美元的海盗公司 | 摸鱼系列
  16. 3DTouch简单实现
  17. MySQL派生表联表查询记录
  18. What are 20 questions to detect fake data scientists?
  19. 交叉测试、探索性测试的概念、价值、实践
  20. Web API 之 — Beacon

热门文章

  1. ES6 语法糖(一)
  2. 【思前享后】区块链的发展历史
  3. 牛客练习赛51 C、勾股定理 只一边求另外两边 结论
  4. VMware虚拟机网络连接的3种方式
  5. 《吴军:科技史纲60讲》走近科技文明世界
  6. 艾特网能“高效节能三板斧”亮相第22届机房协会年会
  7. 【shell】shell 函数
  8. SAP物料凭证中的凭证类型交易/事件
  9. C语言链表超简单教程
  10. 煤炭价格预测:基于matlab的时间序列分析(主要流程+完整代码)