点击上方“AI公园”,关注公众号,选择加“星标“或“置顶”


作者:Vaibhav Kumar

编译:ronghuaiyang

导读

这篇文章详细解析了PyTorch的自动求导机制,让你了解PyTorch的核心魔法。

在这个过程中,它从不显式地构造整个雅可比矩阵。直接计算JVP通常更简单、更有效。

我们都同意,当涉及到大型神经网络时,我们都不擅长微积分。通过显式求解数学方程来计算这样大的复合函数的梯度是不现实的,特别是这些曲线存在于大量的维数中,是无法理解的。

要处理14维空间中的超平面,想象一个三维空间,大声地对自己说“14”。每个人都这么做——Geoffrey Hinton

这就是PyTorch的autograd发挥作用的地方。它抽象了复杂的数学,帮助我们“神奇地”计算高维曲线的梯度,只需要几行代码。这篇文章试图描述autograd的魔力。

PyTorch基础

在进一步讨论之前,我们需要了解一些基本的PyTorch概念。

张量:简单地说,它只是PyTorch中的一个n维数组。张量支持一些额外的增强,这使它们独一无二:除了CPU,它们可以加载或GPU更快的计算。在设置.requires_grad = True的时候,他们开始形成一个反向图,跟踪应用于他们的每个操作,使用所谓的动态计算图(DCG)计算梯度(后面会进一步解释)。

在早期版本的PyTorch中,使用torch.autograd.Variable类用于创建支持梯度计算和操作跟踪的张量,但截至PyTorch v0.4.0,Variable类已被禁用。torch.Tensortorch.autograd.Variable现在是同一个类。更准确地说, torch.Tensor能够跟踪历史并表现得像旧的Variable

 import torch import numpy as np

 x = torch.randn(2, 2, requires_grad = True)

 # From numpy x = np.array([1., 2., 3.]) #Only Tensors of floating point dtype can require gradients x = torch.from_numpy(x) # Now enable gradient x.requires_grad_(True) # _ above makes the change in-place (its a common pytorch thing)

创建启用梯度的张量的各种方法的代码

注意:根据PyTorch的设计,梯度只能计算浮点张量,这就是为什么我创建了一个浮点类型的numpy数组,然后将它设置为启用梯度的PyTorch张量。

Autograd:这个类是一个计算导数的引擎(更精确地说是雅克比向量积)。它记录了梯度张量上所有操作的一个图,并创建了一个称为动态计算图的非循环图。这个图的叶节点是输入张量,根节点是输出张量。梯度是通过跟踪从根到叶的图形,并使用链式法则将每个梯度相乘来计算的。

神经网络和反向传播

神经网络只不过是经过精心调整(训练)以输出所需结果的复合数学函数。调整或训练是通过一种称为反向传播的出色算法完成的。反向传播用来计算相对于输入权值的损失梯度,以便以后更新权值,最终减少损失。

在某种程度上,反向传播只是链式法则的一个花哨的名字—— Jeremy Howard

创建和训练神经网络包括以下基本步骤:

  1. 定义体系结构

  2. 使用输入数据在体系结构上向前传播

  3. 计算损失

  4. 反向传播,计算每个权重的梯度

  5. 使用学习率更新权重

损失变化引起的输入权值的微小变化称为该权值的梯度,并使用反向传播计算。然后使用梯度来更新权值,使用学习率来整体减少损失并训练神经网络。

这是以迭代的方式完成的。对于每个迭代,都要计算几个梯度,并为存储这些梯度函数构建一个称为计算图的东西。PyTorch通过构建一个动态计算图(DCG)来实现这一点。此图在每次迭代中从头构建,为梯度计算提供了最大的灵活性。例如,对于前向操作(函数)Mul ,向后操作函数MulBackward被动态集成到后向图中以计算梯度。

动态计算图

支持梯度的张量(变量)和函数(操作)结合起来创建动态计算图。数据流和应用于数据的操作在运行时定义,从而动态地构造计算图。这个图是由底层的autograd类动态生成的。你不必在启动训练之前对所有可能的路径进行编码——你运行的是你所区分的。

一个简单的DCG用于两个张量的乘法会是这样的:

带有requires_grad = False的DCG

图中的每个点轮廓框是一个变量,紫色矩形框是一个操作。

每个变量对象都有几个成员,其中一些成员是:

Data:它是一个变量持有的数据。x持有一个1x1张量,其值等于1.0,而y持有2.0。z持有两个的乘积,即2.0。

requires_grad:这个成员(如果为true)开始跟踪所有的操作历史,并形成一个用于梯度计算的向后图。对于任意张量a,可以按如下方式对其进行原地处理:a.requires_grad_(True)

grad: grad保存梯度值。如果requires_grad 为False,它将持有一个None值。即使requires_grad 为真,它也将持有一个None值,除非从其他节点调用.backward()函数。例如,如果你对out关于x计算梯度,调用out.backward(),则x.grad的值为∂out/∂x

grad_fn:这是用来计算梯度的向后函数。

is_leaf:如果:

  1. 它被一些函数显式地初始化,比如x = torch.tensor(1.0)x = torch.randn(1, 1)(基本上是本文开头讨论的所有张量初始化方法)。

  2. 它是在张量的操作之后创建的,所有张量都有requires_grad = False

  3. 它是通过对某个张量调用.detach()方法创建的。

在调用backward()时,只计算requires_gradis_leaf同时为真的节点的梯度。

当打开 requires_grad = True时,PyTorch将开始跟踪操作,并在每个步骤中存储梯度函数,如下所示:

requires_grad = True的DCG

在PyTorch下生成上图的代码是:

Backward()函数

Backward函数实际上是通过传递参数(默认情况下是1x1单位张量)来计算梯度的,它通过Backward图一直到每个叶节点,每个叶节点都可以从调用的根张量追溯到叶节点。然后将计算出的梯度存储在每个叶节点的.grad中。请记住,在正向传递过程中已经动态生成了后向图。backward函数仅使用已生成的图形计算梯度,并将其存储在叶节点中。

让我们分析以下代码:

 import torch # Creating the graph x = torch.tensor(1.0, requires_grad = True) z = x ** 3 z.backward() #Computes the gradient print(x.grad.data) #Prints '3' which is dz/dx

需要注意的一件重要事情是,当调用z.backward()时,一个张量会自动传递为z.backward(torch.tensor(1.0))torch.tensor(1.0)是用来终止链式法则梯度乘法的外部梯度。这个外部梯度作为输入传递给MulBackward函数,以进一步计算x的梯度。传递到.backward()中的张量的维数必须与正在计算梯度的张量的维数相同。例如,如果梯度支持张量x和y如下:

 x = torch.tensor([0.0, 2.0, 8.0], requires_grad = True) y = torch.tensor([5.0 , 1.0 , 7.0], requires_grad = True) z = x * y

然后,要计算z关于x或者y的梯度,需要将一个外部梯度传递给z.backward()函数,如下所示:

 z.backward(torch.FloatTensor([1.0, 1.0, 1.0])

z.backward() 会给出 RuntimeError: grad can be implicitly created only for scalar outputs

反向函数传递的张量就像梯度加权输出的权值。从数学上讲,这是一个向量乘以非标量张量的雅可比矩阵(本文将进一步讨论),因此它几乎总是一个维度的单位张量,与 backward张量相同,除非需要计算加权输出。

tldr :向后图是由autograd类在向前传递过程中自动动态创建的。Backward()只是通过将其参数传递给已经生成的反向图来计算梯度。

数学—雅克比矩阵和向量

从数学上讲,autograd类只是一个雅可比向量积计算引擎。雅可比矩阵是一个非常简单的单词,它表示两个向量所有可能的偏导数。它是一个向量相对于另一个向量的梯度。

注意:在这个过程中,PyTorch从不显式地构造整个雅可比矩阵。直接计算JVP (Jacobian vector product)通常更简单、更有效。

如果一个向量X = [x1, x2,…xn]通过f(X) = [f1, f2,…fn]来计算其他向量,则雅可比矩阵(J)包含以下所有偏导组合:

雅克比矩阵

上面的矩阵表示f(X)相对于X的梯度。

假设一个启用PyTorch梯度的张量X

X = [x1,x2,…,xn](假设这是某个机器学习模型的权值)

X经过一些运算形成一个向量Y

Y = f(X) = [y1, y2,…,ym]

然后使用Y计算标量损失l。假设向量v恰好是标量损失l关于向量Y的梯度,如下:

向量v称为grad_tensor,并作为参数传递给backward() 函数。

为了得到损失的梯度l关于权重X的梯度,雅可比矩阵J是向量乘以向量v

这种计算雅可比矩阵并将其与向量v相乘的方法使PyTorch能够轻松地为非标量输出提供外部梯度。

—END—

英文原文:https://towardsdatascience.com/pytorch-autograd-understanding-the-heart-of-pytorchs-magic-2686cd94ec95

请长按或扫描二维码关注本公众号

喜欢的话,请给我个好看吧

PyTorch的自动求导机制详细解析,PyTorch的核心魔法相关推荐

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

    Introduce Pytorch Autograd库 (自动求导机制) 是训练神经网络时,反向误差传播(BP)算法的核心. 本文通过logistic回归模型来介绍Pytorch的自动求导机制.首先, ...

  2. Pytorch教程入门系列4----Autograd自动求导机制

    系列文章目录 文章目录 系列文章目录 前言 一.Autograd是什么? 二.Autograd的使用方法 1.在tensor中指定 2.重要属性 三.Autograd的进阶知识 1.动态计算图 2.梯 ...

  3. PyTorch 笔记Ⅱ——PyTorch 自动求导机制

    文章目录 Autograd: 自动求导机制 张量(Tensor) 梯度 使用PyTorch计算梯度数值 Autograd 简单的自动求导 复杂的自动求导 Autograd 过程解析 扩展Autogra ...

  4. PyTorch的计算图和自动求导机制

    文章目录 PyTorch的计算图和自动求导机制 自动求导机制简介 自动求导机制实例 梯度函数的使用 计算图构建的启用和禁用 总结 PyTorch的计算图和自动求导机制 自动求导机制简介 PyTorch ...

  5. Pytorch学习(一)—— 自动求导机制

    现在对 CNN 有了一定的了解,同时在 GitHub 上找了几个 examples 来学习,对网络的搭建有了笼统地认识,但是发现有好多基础 pytorch 的知识需要补习,所以慢慢从官网 API 进行 ...

  6. 【PyTorch基础教程2】自动求导机制(学不会来打我啊)

    文章目录 第一部分:深度学习和机器学习 一.机器学习任务 二.ML和DL区别 (1)数据加载 (2)模型实现 (3)训练过程 第二部分:Pytorch部分 一.学习资源 二.自动求导机制 2.1 to ...

  7. 【PyTorch学习(三)】Aurograd自动求导机制总结

    ​Aurograd自动求导机制总结 PyTorch中,所有神经网络的核心是 autograd 包.autograd 包为tensor上的所有操作提供了自动求导机制.它是一个在运行时定义(define- ...

  8. 【深度学习】pytorch自动求导机制的理解 | tensor.backward() 反向传播 | tensor.detach()梯度截断函数 | with torch.no_grad()函数

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一.pytorch里自动求导的基础概念 1.1.自动求导 requires_grad=True 1.2.求导 requ ...

  9. 深度学习框架 TensorFlow:张量、自动求导机制、tf.keras模块(Model、layers、losses、optimizer、metrics)、多层感知机(即多层全连接神经网络 MLP)

    日萌社 人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度学习实战(不定时更新) 安装 TensorFlow2.CUDA10.cuDNN7.6. ...

  10. 深度学习修炼(三)——自动求导机制

    文章目录 致谢 3 自动求导机制 3.1 传播机制与计算图 3.1.1 前向传播 3.1.2 反向传播 3.2 自动求导 3.3 再来做一次 3.4 线性回归 3.4.1 回归 3.4.2 线性回归的 ...

最新文章

  1. object.ReferenceEquals(a,b)
  2. 为什么我劝你不要当数据科学家?
  3. UVa1588 - Kickdown
  4. 【干货】理发师都知道的产品经理最容易犯的几个错误
  5. Java中return的用法
  6. 微课系列(二):列表方法sort()和内置函数sorted()的稳定排序特点
  7. python中print后面加逗号
  8. BigGAN学会“七十二变”:跟着视频模仿动物,看到啥就能变啥
  9. python错误笔记
  10. avformat_open_input 支持的参数
  11. AdapterView与Adapter
  12. foxmail信纸设置html,教你如何设置Foxmail信纸花样?
  13. 【52】NVMe暴力热插拔对系统的要求
  14. DOM事件+正则表达式
  15. SpringClude--feign介绍
  16. 李彦宏:我不是传奇(网络转载)
  17. 玩转Android之Activity详细剖析
  18. 【转】利用tmail.exe 命令参数来发送邮件
  19. 有你的小镇漫画下载[濑尾公治]
  20. Texworks编译.bib增加参考文献

热门文章

  1. rust启动错误ple_Rust 错误处理
  2. MySQL 名次查询
  3. 手机网页点击按钮给指定号码发送短信
  4. 修改服务器的ip地址的命令,使用命令提示符更改IP地址和DNS服务器 | MOS86
  5. signature=89d6821c2fe7d31483f21edf9c96c63b,Forage harvester
  6. 苹果截屏快捷键_Mac进阶:掌握这 5 个冷门快捷键,让Mac更好用
  7. Redis基础知识点面试手册
  8. Gerrit error:remote: ERROR: The following addresses are currently registered:XXX
  9. STM8S003FP6 TIM4配置
  10. Java多线程模拟医院排号叫号系统