pytorch backward使用解析

news2024/10/7 11:21:44

目录

  • 前言
  • backward函数官方文档
  • backward理解
    • Jacobian矩阵
    • vector-Jacobian product的计算
    • vector-Jacobian product的例子理解
  • 输入和输出为标量或向量时的计算
    • 输入为标量,输出为标量
    • 输入为标量,输出为向量
    • 输入为向量,输出为标量
    • 输入为标量,输出为向量
  • 额外例子:输出为标量,gradient为向量
    • 输入为标量,输出为标量,gradient为向量
    • 输入为向量,输出为标量,gradient为向量
  • 总结

前言

torch版本为v1.13。

backward函数官方文档

torch.Tensor.backward:计算当前tensor相对于图的叶子的梯度。

叶子可以理解为自己创建的变量。使用链式法则,图是可微的。如果张量不是标量,并且需要梯度,该函数还需要指定gradient。它应该是匹配类型和位置的tensor,包含微分函数相对于self的梯度(???)。

这个函数在叶子中累计梯度,在调用它之前,可能需要将.grad属性归零或将它们设置为 None 。

参数:

  • gradient (Tensor or None) – 关于tensor的梯度。如果它是一个tensor,会自动转为不需要grad的Tensor,除非create_graph为True。None值可以指定为标量Tensor或不需要grad的Tensor。如果None值是可接受的,那么该参数是可选参数。
  • retain_graph (bool, optional) – 如果为False,用于计算grads的graph将被释放。注意,在几乎所有情况下,都不需要将此选项设置为 True,而且通常可以以更有效的方式解决。 默认为 create_graph 的值。
  • create_graph (bool, optional) – 默认为False。如果为True,导数的图将会被构建,允许计算更高阶的导数衍生品(derivative products)。
  • inputs (sequence of Tensor) – 将梯度累积到inputs 的 .grad 中。其他的Tensors将会被忽略。如果未提供,则梯度将累积到用于计算 attr::tensors 的所有叶张量中。

backward理解

在这里插入图片描述

Jacobian矩阵

参考:wolfram-Jacobian
x = ( x 1 , x 2 , ⋯   , x n ) T \bold{x}=(x_1,x_2,\cdots,x_n)^T x=(x1,x2,,xn)T y = f ( x ) \bold{y}=f(\bold{x}) y=f(x),则有:
y = [ y 1 y 2 ⋮ y m ] = [ f 1 ( x ) f 2 ( x ) ⋮ f m ( x ) ] = [ f 1 ( x 1 , x 2 , ⋯   , x n ) f 2 ( x 1 , x 2 , ⋯   , x n ) ⋮ f m ( x 1 , x 2 , ⋯   , x n ) ] \bold{y}= \begin{bmatrix} y_1 \\ y_2 \\ \vdots \\ y_m \\ \end{bmatrix}= \begin{bmatrix} f_1(\bold{x}) \\ f_2(\bold{x}) \\ \vdots \\ f_m(\bold{x}) \\ \end{bmatrix}= \begin{bmatrix} f_1(x_1,x_2,\cdots,x_n) \\ f_2(x_1,x_2,\cdots,x_n) \\ \vdots \\ f_m(x_1,x_2,\cdots,x_n) \\ \end{bmatrix} y= y1y2ym = f1(x)f2(x)fm(x) = f1(x1,x2,,xn)f2(x1,x2,,xn)fm(x1,x2,,xn) ,则 y \bold{y} y 关于 x \bold{x} x 的梯度是一个雅可比矩阵:
J ( x 1 , x 2 , ⋯   , x n ) = ∂ ( y 1 , ⋯   , y m ) ∂ ( x 1 , ⋯   , x n ) = [ ∂ y 1 ∂ x 1 ∂ y 1 ∂ x 2 ⋯ ∂ y 1 ∂ x n ∂ y 2 ∂ x 1 ∂ y 2 ∂ x 2 ⋯ ∂ y 2 ∂ x n ⋮ ⋮ ⋱ ⋮ ∂ y m ∂ x 1 ∂ y m ∂ x 2 ⋯ ∂ y m ∂ x n ] J(x_1,x_2,\cdots,x_n) = {\frac {\partial(y_1,\cdots,y_m)} {\partial(x_1,\cdots,x_n)}}= \begin{bmatrix} \frac{\partial y_{1}}{\partial x_{1}} & \frac{\partial y_{1}}{\partial x_{2}} & \cdots &\frac{\partial y_{1}}{\partial x_{n}} \\ \frac{\partial y_{2}}{\partial x_{1}}& \frac{\partial y_{2}}{\partial x_{2}} & \cdots & \frac{\partial y_{2}}{\partial x_{n}}\\ \vdots &\vdots & \ddots & \vdots \\ \frac{\partial y_{m}}{\partial x_{1}}& \frac{\partial y_{m}}{\partial x_{2}} &\cdots & \frac{\partial y_{m}}{\partial x_{n}} \end{bmatrix} J(x1,x2,,xn)=(x1,,xn)(y1,,ym)= x1y1x1y2x1ymx2y1x2y2x2ymxny1xny2xnym

vector-Jacobian product的计算

参考:
The “gradient” argument in Pytorch’s “backward” function
详解Pytorch 自动微分里的(vector-Jacobian product)-知乎

backward(torch.autograd.backward或Tensor.backward)实现的是vector-Jacobian product,即矢量-雅可比积,Jacobian容易理解,这里的vector(设为 v v v)就是backward的gradient参数,有很多种理解:

  • y i y_i yi x i x_i xi 的偏导数沿 v v v上的投影, v v v的默认方向为 v = ( 1 , 1 , ⋯   , 1 ) v=(1,1,\cdots,1) v=(1,1,,1)
  • 各个分量函数关于 x i x_i xi偏好的权重

值得注意的是, v v v 的维度与输出保持一致,可正可负

所以,vector-Jacobian product的形式为:
v ⋅ J = [ v 1 , v 2 , ⋯   , v m ] ⋅ [ ∂ y 1 ∂ x 1 ∂ y 1 ∂ x 2 ⋯ ∂ y 1 ∂ x n ∂ y 2 ∂ x 1 ∂ y 2 ∂ x 2 ⋯ ∂ y 2 ∂ x n ⋮ ⋮ ⋱ ⋮ ∂ y m ∂ x 1 ∂ y m ∂ x 2 ⋯ ∂ y m ∂ x n ] = [ ∑ i = 0 m ∂ y i ∂ x 1 v i ,     ∑ i = 0 m ∂ y i ∂ x 2 v i ,     ⋯   ,     ∑ i = 0 m ∂ y i ∂ x n v i ] \begin{aligned} \bold{v} \cdot J &= [v_1,v_2,\cdots,v_m]\cdot \begin{bmatrix} \frac{\partial y_{1}}{\partial x_{1}} & \frac{\partial y_{1}}{\partial x_{2}} & \cdots &\frac{\partial y_{1}}{\partial x_{n}} \\ \frac{\partial y_{2}}{\partial x_{1}}& \frac{\partial y_{2}}{\partial x_{2}} & \cdots & \frac{\partial y_{2}}{\partial x_{n}}\\ \vdots &\vdots & \ddots & \vdots \\ \frac{\partial y_{m}}{\partial x_{1}}& \frac{\partial y_{m}}{\partial x_{2}} &\cdots & \frac{\partial y_{m}}{\partial x_{n}} \end{bmatrix}\\ &= \begin{bmatrix} \sum_{i=0}^{m}{\frac {\partial y_i} {\partial x_1}v_i},\,\,\, \sum_{i=0}^{m}{\frac {\partial y_i} {\partial x_2}v_i},\,\,\, \cdots,\,\,\, \sum_{i=0}^{m}{\frac {\partial y_i} {\partial x_n}v_i} \end{bmatrix} \end{aligned} vJ=[v1,v2,,vm] x1y1x1y2x1ymx2y1x2y2x2ymxny1xny2xnym =[i=0mx1yivi,i=0mx2yivi,,i=0mxnyivi]

这就是输出进行backward之后,叶子张量的.grad值。

vector-Jacobian product的例子理解

y = x 2 y=x^2 y=x2为例进行解释:
代码1:

x = torch.tensor([1,2,3.], requires_grad=True)
y = x**2
y.backward(gradient=torch.tensor([1,1,1.]))
print(x.grad)
"""
输出:
tensor([2., 4., 6.])
"""

代码2:

x = torch.tensor([1,2,3.], requires_grad=True)
y = x**2
y.backward(gradient=torch.tensor([10,-10,20.]))
print(x.grad)
"""
输出:
tensor([ 20., -40., 120.])
"""

可以发现,代码2相比于代码1,结果放大了gradient倍。设上述代码中的 x = ( x 1 , x 2 , x 3 ) \bold{x}=(x_1,x_2,x_3) x=(x1,x2,x3),则 y = ( y 1 , y 2 , y 3 ) = ( x 1 2 , x 2 2 , x 3 2 ) \bold{y}=(y_1,y_2,y_3)=(x_1^2,x_2^2,x_3^2) y=(y1,y2,y3)=(x12,x22,x32),gradient为 v = ( v 1 , v 2 , v 3 ) \bold{v}=(v_1,v_2,v_3) v=(v1,v2,v3)。使用vector-Jacobian product公式可得:

v ⋅ J = [ v 1 , v 2 , v 3 ] [ ∂ y 1 ∂ x 1 ∂ y 1 ∂ x 2 ∂ y 1 ∂ x n ∂ y 2 ∂ x 1 ∂ y 2 ∂ x 2 ∂ y 2 ∂ x n ∂ y 3 ∂ x 1 ∂ y 3 ∂ x 2 ∂ y 3 ∂ x n ] = [ ∑ i = 0 3 ∂ y i ∂ x 1 v i ,     ∑ i = 0 3 ∂ y i ∂ x 2 v i ,     ∑ i = 0 3 ∂ y i ∂ x 3 v i ] = [ 2 x 1 v 1 , 2 x 2 v 2 , 2 x 3 v 3 ] = [ 2 v 1 , 4 v 2 , 6 v 3 ] \begin{aligned} \bold{v} \cdot J &= [v_1,v_2,v_3] \begin{bmatrix} \frac{\partial y_{1}}{\partial x_{1}} & \frac{\partial y_{1}}{\partial x_{2}} &\frac{\partial y_{1}}{\partial x_{n}} \\ \frac{\partial y_{2}}{\partial x_{1}}& \frac{\partial y_{2}}{\partial x_{2}} & \frac{\partial y_{2}}{\partial x_{n}}\\ \frac{\partial y_{3}}{\partial x_{1}}& \frac{\partial y_{3}}{\partial x_{2}} & \frac{\partial y_{3}}{\partial x_{n}} \end{bmatrix}\\ &= \begin{bmatrix} \sum_{i=0}^{3}{\frac {\partial y_i} {\partial x_1}v_i},\,\,\, \sum_{i=0}^{3}{\frac {\partial y_i} {\partial x_2}v_i},\,\,\, \sum_{i=0}^{3}{\frac {\partial y_i} {\partial x_3}v_i} \end{bmatrix} \\ &=\begin{bmatrix}2x_1v_1,2x_2v_2,2x_3v_3\end{bmatrix} \\ &=\begin{bmatrix}2v_1,4v_2,6v_3\end{bmatrix} \end{aligned} vJ=[v1,v2,v3] x1y1x1y2x1y3x2y1x2y2x2y3xny1xny2xny3 =[i=03x1yivi,i=03x2yivi,i=03x3yivi]=[2x1v1,2x2v2,2x3v3]=[2v1,4v2,6v3]

分别将 v = ( 1 , 1 , 1. ) \bold{v}=(1,1,1.) v=(1,1,1.) v = ( 10 , − 10 , 20. ) \bold{v}=(10,-10,20.) v=(10,10,20.) 带入可得代码结果。

输入和输出为标量或向量时的计算

输入为标量,输出为标量

代码:

x = torch.tensor(2., requires_grad=True)
y = x**2+x
y.backward(gradient=torch.tensor(1.))
print(x.grad)
"""
输出:
tensor([5.])
"""

解释:
x = x 1 \bold{x}=x_1 x=x1,则 y = y 1 = x 1 2 + x 1 \bold{y}=y_1=x_1^2+x_1 y=y1=x12+x1,gradient为 v = v 1 \bold{v}=v_1 v=v1,则:
v ⋅ J = [ v 1 ] ⋅ [ ∂ y 1 ∂ x 1 ] = [ v 1 ] ⋅ [ 2 x 1 + 1 ] = [ 1 ] ⋅ [ 2 × 2 + 1 ] = 5 \begin{aligned} \bold{v} \cdot J &= [v_1]\cdot[\frac {\partial y_1} {\partial x_1}]\\ &=[v_1]\cdot[2x_1+1]\\ &=[1]\cdot[2\times2+1]\\ &=5 \end{aligned} vJ=[v1][x1y1]=[v1][2x1+1]=[1][2×2+1]=5

输入为标量,输出为向量

代码:

x = torch.tensor(1., requires_grad=True)
y = torch.empty(2)
y[0] = x**2
y[1] = x**3
y.backward(gradient=torch.tensor([1,2.]))
print(x.grad)
"""
输出:
tensor(8.)
"""

解释:
x = x 1 \bold{x}=x_1 x=x1,则 y = [ y 1 , y 2 ] = [ x 1 2 , x 1 3 ] \bold{y}=[y_1,y_2]=[x_1^2,x_1^3] y=[y1,y2]=[x12,x13],gradient为 v = [ v 1 , v 2 ] \bold{v}=[v_1,v_2] v=[v1,v2],则:
v ⋅ J = [ v 1 , v 2 ] ⋅ [ ∂ y 1 ∂ x 1 ∂ y 2 ∂ x 1 ] = [ v 1 , v 2 ] ⋅ [ 2 x 1 3 x 1 2 ] = [ 1 , 2 ] ⋅ [ 2 3 ] = 8 \begin{aligned} \bold{v} \cdot J &= [v_1,v_2]\cdot \begin{bmatrix} \frac {\partial y_1} {\partial x_1} \\ \frac {\partial y_2} {\partial x_1} \end{bmatrix}\\ &= [v_1,v_2]\cdot \begin{bmatrix} 2x_1 \\ 3x_1^2 \end{bmatrix}\\ &= [1,2]\cdot \begin{bmatrix} 2 \\ 3 \end{bmatrix}\\ &=8 \end{aligned} vJ=[v1,v2][x1y1x1y2]=[v1,v2][2x13x12]=[1,2][23]=8


输入为向量,输出为标量

代码:

x = torch.tensor([1.,2,3], requires_grad=True)
y = torch.sum(x**2)
y.backward()
print(x.grad)
"""
输出:
tensor([2., 4., 6.])
"""

解释:
x = [ x 1 , x 2 , x 3 ] \bold{x}=[x_1,x_2,x_3] x=[x1,x2,x3],则 y = y 1 = x 1 2 + x 2 2 + x 3 2 \bold{y}=y_1=x_1^2+x_2^2+x_3^2 y=y1=x12+x22+x32,gradient为 v = [ v 1 ] \bold{v}=[v_1] v=[v1],则:
v ⋅ J = [ v 1 ] ⋅ [ ∂ y 1 ∂ x 1 ∂ y 1 ∂ x 2 ∂ y 1 ∂ x 3 ] = [ v 1 ] ⋅ [ 2 x 1 2 x 2 2 x 3 ] = [ 1 ] ⋅ [ 2 4 6 ] = [ 2 4 6 ] \begin{aligned} \bold{v} \cdot J &= [v_1]\cdot \begin{bmatrix} \frac {\partial y_1} {\partial x_1} & \frac {\partial y_1} {\partial x_2} & \frac {\partial y_1} {\partial x_3} \end{bmatrix}\\ &= [v_1]\cdot \begin{bmatrix} 2x_1 & 2x_2 & 2x_3 \end{bmatrix}\\ &= [1]\cdot \begin{bmatrix} 2&4&6 \end{bmatrix}\\ &= \begin{bmatrix} 2&4&6 \end{bmatrix}\\ \end{aligned} vJ=[v1][x1y1x2y1x3y1]=[v1][2x12x22x3]=[1][246]=[246]

输入为标量,输出为向量

参见上一节 vector-Jacobian product的例子理解

额外例子:输出为标量,gradient为向量

在上一节的例子中,gradient的维度与输出维度保持一致,本节探索gradient的维度与输出维度不一致的情况。

输入为标量,输出为标量,gradient为向量

x = torch.tensor(2., requires_grad=True)
y = x**2+x
y.backward(gradient=torch.tensor([1.,10]))
print(x.grad)

结果:报错

RuntimeError: Mismatch in shape: grad_output[0] has a shape of torch.Size([4]) and output[0] has a shape of torch.Size([]).

输入为向量,输出为标量,gradient为向量

x = torch.tensor([1.,2,3], requires_grad=True)
y = torch.sum(x**2)
y.backward(gradient=torch.tensor([1,2.]))
print(x.grad)

结果:报错

RuntimeError: Mismatch in shape: grad_output[0] has a shape of torch.Size([2]) and output[0] has a shape of torch.Size([]).

总结

  • gradient默认为1,其维度应与输出维度保持一致;
  • gradient类似于在梯度前面乘以一个动量,类似于学习率,不过可正可负(个人理解);

■ \blacksquare

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/194307.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从零编写linux0.11 - 第十章 文件系统(二)

从零编写linux0.11 - 第十章 文件系统(二) 编程环境:Ubuntu 20.04、gcc-9.4.0 代码仓库:https://gitee.com/AprilSloan/linux0.11-project linux0.11源码下载(不能直接编译,需进行修改) 本章…

学会这7个常见问题和答案,让你下一次JavaScript面试获得高分

在本文中,我将涵盖您在JavaScript 面试中可能遇到的最常见问题,并提供详细的答案和示例,以帮助您在竞争中脱颖而出。无论您是初学者还是经验丰富的开发人员,本指南都会让您有信心打动面试官并找到工作。1️⃣ 什么是 JavaScript&a…

C++——继承

作为面向对象的语言,c开发了名为继承的机制,它是c中代码复用的重要手段; 允许程序员在保持原有特性的基础(基类)上进行扩展,并产生新的类(派生类),这就是继承。 继承的格…

剑指 Offer 64. 求1+2+…+n

剑指 Offer 64. 求12…nhttps://leetcode.cn/problems/qiu-12n-lcof/ 求 12...n ,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。 示例 1: 输入: n 3 输出: 6 示例 2: 输入…

Linux——安装JDK和OpenJDK【多种方法】

目录 一、Linux安装OpenJDK 1、查看系统是否有自带的版本 2、删除OpenJDK 3、本地下载OpenJDK 4、无法本地下载,也可以使用命令下载(方法1) 4、无法本地下载,也可以使用命令下载(方法2) 5、拓展 三…

3-3-多线程-TheadLocal内存泄漏

Java TheadLocal内存泄漏 1、引言 组内来了一个实习生,看这小伙子春光满面、精神抖擞、头发微少,我心头一喜:绝对是个潜力股。为了帮助小伙子快速成长,我给他分了一个需求,这不需求刚上线几天就出网上问题了&#x1…

C++ 树进阶系列之线段树和它的延迟更新

1. 前言 线段树和树状数组有相似之处,可以用于解决区间类型的问题。 但两者又各个千秋,树状数组本质是数组,有着树的形,可以借用树的一些概念。线段树是典型的二叉树结构,无论神和形都是树,可以应用树的所…

用 Python 的 tkinter 模块编写一个好看又强大的中国象棋

继上次我的第一版的《中国象棋》程序之后,我又编写了第二版的《中国象棋》程序,关注我的粉丝知道,我在第一篇《中国象棋》的文章末尾说了,我会出第二版的,对第一版感兴趣的朋友们,可以去看看,也…

VueJS 之样式冲突与样式穿透

文章目录参考描述样式冲突现象scoped原理样式穿透深度选择器使用原理顶层元素局限性参考 项目描述搜索引擎Bing哔哩哔哩黑马程序员 描述 项目描述Edge109.0.1518.70 (正式版本) (64 位)操作系统Windows 10 专业版vue/cli5.0.8npm8.19.3VueJS2.6.14 样式冲突 在使用 Vue 进行…

大文件上传/下载

一、前言 大文件上传下载一直以来是前端常用且常考的热门话题。本文将分别介绍大文件上传/下载的思路和前端实现代码。 二、分片上传 整体流程 对文件做切片,选择文件后,对获取到的file对象使用slice方法可以将其按照制定的大小进行切片,…

使用matplotlib,pylab进行python绘图

一提到python绘图,matplotlib是不得不提的python最著名的绘图库,它里面包含了类似matlab的一整套绘图的API。因此,作为想要学习python绘图的童鞋们就得在自己的python环境中安装matplotlib库了,安装方式这里就不多讲,方…

openmmlab学习打卡1

openmmlab学习打卡1通用视觉框架 OpenMMLab通过 conda 安装通用视觉框架 OpenMMLab 基于pytorch实现 其中: 分类算法在 mmclassification 模块下 目标检测在 mmdetection 模块下 分割模型在 mmsegmentation 模块下(openmmlab 2.0 版本中加入&#xff09…

洛谷P1885 Moo —— 搜索

This way 题意: 奶牛 Bessie 最近在学习字符串操作,它用如下的规则逐一的构造出新的字符串: S(0)S(0) S(0) moo S(1)S(0)S(1) S(0) S(1)S(0) m ooo S(0) S(0) S(0) moo m ooo moo moomooomoo S(2)S(1)S(2) S(1) S(2)S(1) m oooo S(…

无js实现拖拽边框改变大小的笔记

前言 最近刷抖音看到一款游戏"拣爱",看到这个人手动拖动的很有意思,就想着能不能前端实现,来学习学习,虽然说最终的效果没有gif图片那么好,但是也算实现了,吧… 具体原理 利用resize属性所出现的小拖拽条 再配合::-webkit-scrollbar设置拖拽区域宽度,高度,结合opac…

手动签发证书配置nginx

openssl和ssh基本用法 通过OpenSSL工具生成证书 创建私钥 openssl genrsa -des3 -out server.key 2048 注意,centos版本如果是CentOS Linux release 8.0.1905 (Core)版本,私钥长度不能设置成1024位,必须2048位。不然再最后启动nginx时会出…

java之数组模块

数组定义格式1.1数组概述一次性声明大量的用于存储数据的变量要存储的数据通常都是同类型数据,例如:考试成绩1.2什么是数组数组(array)是一种用于存储多个相同类型数据的存储模型1.3数组的定义格式格式一:数据类型[] 变量名范例: …

h5实现相机

什么是取景器 取景器是什么?取景器是相机的一个专业术语,在前端就是扫描拍照 取景器的实现原理 请求手机的一个媒体类型的视频轨道,利用一个div或者图片作为上层蒙层,然后在利用canvas绘制视频中某一帧的画面绘制为图片。 前期…

HTML基础知识

一个网站由两部分组成:前端和后端。前端主流语言目前是HTML、CSS、JS等。HTML只是描述了页面的内容(骨架),CSS才是描述了页面的样式。HTML结构HTML标签HTML代码是由“标签”构成的,HTML描述了页面上有什么东西&#xf…

数字化转型导师坚鹏:银行数字化转型为什么需要融合王阳明心学

在BLM银行数字化转型方法论中,我之所以融合BLM模型与王阳明心学,作为一个工科背景并拥有多年软硬件产品研发经验的人来说,深刻地知道很多人利用了科技的力量做了大量的恶事,而不是善事,如黑客大量盗取、泄漏、贩卖客户…

ESLint 的一些理解

ESLint ESLint 是在 ECMAScript/JavaScript 代码中识别和报告模式匹配的工具,它的目标是保证代码的一致性和避免错误。 为什么要使用ESLint 有的可以帮我们避免错误;有的可以帮我们写出最佳实践的代码;有的可以帮我们规范变量的使用方式&a…