pytorch教程之自动求导机制(AUTOGRAD)-从梯度和Jacobian矩阵讲起
文章目录
- 1. 梯度和Jacobian矩阵
- 2. pytorch求变量导数的过程
1. 梯度和Jacobian矩阵
设f(x)∈R1f(x)\in R^1f(x)∈R1是关于向量x∈Rnx\in R^nx∈Rn的函数,则它关于xxx的导数定义为:
df(x)dx:=[∂f(x)∂xi]∈Rn(1-1)\frac{df(x)}{dx}:=\left[\frac{\partial f(x)}{\partial x_i}\right]\in R^{n}\tag{1-1} dxdf(x):=[∂xi∂f(x)]∈Rn(1-1)
函数f(x)∈R1f(x)\in R^1f(x)∈R1关于向量x∈Rnx\in R^nx∈Rn的导数是一个列向量,称之为f(x)f(x)f(x)关于xxx的梯度。
df(x)Tdx:=(df(x)dx)T=[∂f(x)∂xi]T∈R1×n(1-2)\frac{df(x)^T}{dx}:=\left(\frac{df(x)}{dx}\right)^T=\left[\frac{\partial f(x)}{\partial x_i}\right]^T\in R^{1\times n}\tag{1-2} dxdf(x)T:=(dxdf(x))T=[∂xi∂f(x)]T∈R1×n(1-2)
如果f(x)∈RMf(x)\in R^Mf(x)∈RM是关于向量x∈Rnx\in R^nx∈Rn的函数向量,则f(x)f(x)f(x)关于xxx的导数定义为:
df(x)dx:=df(x)dxT=[∂f(x)∂x1,∂f(x)∂x2,⋯,∂f(x)∂xn]∈Rm×n(1-3)\frac{df(x)}{dx}:=\frac{df(x)}{dx^T}=\left[\frac{\partial f(x)}{\partial x_1},\frac{\partial f(x)}{\partial x_2},\cdots,\frac{\partial f(x)}{\partial x_n}\right]\in R^{m\times n}\tag{1-3} dxdf(x):=dxTdf(x)=[∂x1∂f(x),∂x2∂f(x),⋯,∂xn∂f(x)]∈Rm×n(1-3)
称上述矩阵为Jacobian矩阵。
一些常用推论:
- 假设v,x∈Rnv,x\in R^nv,x∈Rn:
ddx(vTx)=ddx(xTv)=v(1-4)\frac{d}{dx}(v^Tx)=\frac{d}{dx}(x^Tv)=v\tag{1-4} dxd(vTx)=dxd(xTv)=v(1-4) - 假设y∈R1y\in R^1y∈R1,z∈Rmz\in R^mz∈Rm,x∈Rnx\in R^nx∈Rn,z=g(x)z=g(x)z=g(x),y=f(z):
dydx=(dzdx)Tdydz(1-5)\frac{dy}{dx}=\left(\frac{dz}{dx}\right)^T\frac{dy}{dz}\tag{1-5} dxdy=(dxdz)Tdzdy(1-5)
可以从向量矩阵的维度适配上去理解和记忆,因为dydx∈Rn\frac{dy}{dx}\in R^ndxdy∈Rn,dydz∈Rm\frac{dy}{dz}\in R^mdzdy∈Rm,dzdx∈Rm×n\frac{dz}{dx}\in R^{m\times n}dxdz∈Rm×n,所以必须有上述的公式才能适配。 - 假设y∈Rky\in R^ky∈Rk,z∈Rmz\in R^mz∈Rm,x∈R1x\in R^1x∈R1,z=g(x)z=g(x)z=g(x),y=f(z):
dydx=dydzdzdx(1-6)\frac{dy}{dx}=\frac{dy}{dz}\frac{dz}{dx}\tag{1-6} dxdy=dzdydxdz(1-6) - 假设y∈Rky\in R^ky∈Rk,z∈Rmz\in R^mz∈Rm,x∈Rnx\in R^nx∈Rn,z=g(x)z=g(x)z=g(x),y=f(z):
dydx=dydzdzdx(1-7)\frac{dy}{dx}=\frac{dy}{dz}\frac{dz}{dx}\tag{1-7} dxdy=dzdydxdz(1-7)
2. pytorch求变量导数的过程
在pytorch和TensorFlow中,是不支持张量对张量的求导。这不是因为数学上没法求,而是因为工程实现上比较麻烦。因为向量对向量求导是个矩阵,二阶张量(矩阵)对二阶张量(矩阵)求导得到一个四阶张量,这样很容易会产生阶数爆炸。所以pytorch和TensorFlow(猜测其他深度学习框架也是这样)对外的接口干脆不支持张量对张量求导。如果遇到张量对张量求导的情况,例如向量对向量求导的情况,需要对因变量乘以一个维度一样的向量,转换为标量对向量的求导,这样可以大大减少计算量(具体见后文)。并且,因为pytorch和TensorFlow是为了机器学习/深度学习模型设计的,机器学习/深度模型的求导基本上都是损失函数(标量)对参数的求导,很少直接用到向量对向量求导,因此上述过程是有实际意义和需求的。
假设有一个三维tensor x=[x1,x2,x3]T=[1,2,3]Tx=[x_1,x_2,x_3]^T=[1,2,3]^Tx=[x1,x2,x3]T=[1,2,3]T,另一个三维tensor y:
y=f(x)=[x13+2x22+3x33x1+2x22+x332x1+x23+3x32](2-1)y=f(x)= \begin{bmatrix} {x_1}^3+2{x_2}^2+3x_3 \\ 3x_1+2{x_2}^2+{x_3}^3\\ 2x_1+{x_2}^3+3{x_3}^2 \end{bmatrix} \tag{2-1} y=f(x)=⎣⎡x13+2x22+3x33x1+2x22+x332x1+x23+3x32⎦⎤(2-1)
那么在计算y相对于x的导数时,
dydx=[3x12,4x2,33,4x2,3x322,3x22,6x3](2-2)\frac{dy}{dx}= \begin{bmatrix} &3{x_1}^2,&4x_2,&3 \\ &3,&4{x_2},&3{x_3}^2\\ &2,&3{x_2}^2,&6{x_3} \end{bmatrix} \tag{2-2} dxdy=⎣⎡3x12,3,2,4x2,4x2,3x22,33x326x3⎦⎤(2-2)
在pytorch中实际计算时,不能直接用y对x求导,需要先用一个向量www左乘y,再转置。例如,wT=[3,2,1]w^T=[3,2,1]wT=[3,2,1]。因此,pytorch算的其实是:
dyTdxw=(wTdydx)T=[175281](2-3)\frac{dy^T}{dx}w= \left(w^T\frac{dy}{dx}\right)^T =\begin{bmatrix} 17\\ 52\\ 81\\ \end{bmatrix} \tag{2-3} dxdyTw=(wTdxdy)T=⎣⎡175281⎦⎤(2-3)
www可以理解为是对[∂y1∂x,∂y2∂x,∂y3∂x]T[\frac{\partial y_1}{\partial x},\frac{\partial y_2}{\partial x},\frac{\partial y_3}{\partial x}]^T[∂x∂y1,∂x∂y2,∂x∂y3]T的权重参数。因此我们得到的是y的各个分量的导数的加权求和。
代码如下:
import torch
x1=torch.tensor(1, requires_grad=True, dtype = torch.float)
x2=torch.tensor(2, requires_grad=True, dtype = torch.float)
x3=torch.tensor(3, requires_grad=True, dtype = torch.float)
y=torch.randn(3)
y[0]=x1**3+2*x2**2+3*x3
y[1]=3*x1+2*x2**2+x3**3
y[2]=2*x1+x2**3+3*x3**2
v=torch.tensor([3,2,1],dtype=torch.float)
y.backward(v)
print(x1.grad)
print(x2.grad)
print(x3.grad)
利用链式求导的原理来理解,可以理解为www是(远方)某个标量对yyy的导数。pytorch之所以要这么设计,是因为在机器学习/深度学习模型中,求导的最终目的一般是为了让损失函数最小。损失函数一般都是一个标量,因此无论链式求导的过程多么复杂,中间过程也许有很多向量对向量求导的子过程,但是最开始一定会有一个标量(损失函数)对向量的求导过程,这个导数就是前面的www。
下面看一个带两个隐藏层的神经网络解决线性回归问题的例子,来进一步说明这点。
为了简单起见,考虑batch_size=1的情况。设输入数据为x=[x1,x2]Tx=[x_1,x_2]^Tx=[x1,x2]T,输入层到第一个隐藏层的权重矩阵为
W=[w1Tw2T]=[w11,w12w21,w22](2-4)W=\begin{bmatrix} w_1^T\\ w_2^T \end{bmatrix} = \begin{bmatrix} w_{11},w_{12}\\ w_{21},w_{22}\\ \end{bmatrix} \tag{2-4} W=[w1Tw2T]=[w11,w12w21,w22](2-4)
第一个隐藏层的值为z=[z1,z2]Tz=[z_1,z_2]^Tz=[z1,z2]T,
第一个隐藏层到第二个隐藏层的权重矩阵为
U=[u1Tu2T]=[u11,u12u21,u22](2-5)U=\begin{bmatrix} u_1^T\\ u_2^T \end{bmatrix} = \begin{bmatrix} u_{11},u_{12}\\ u_{21},u_{22}\\ \end{bmatrix} \tag{2-5} U=[u1Tu2T]=[u11,u12u21,u22](2-5)
第二个隐藏层的值为s=[s1,s2]Ts=[s_1,s_2]^Ts=[s1,s2]T,
输出层的值为yyy,隐藏层到输出层的权重参数为v=[v1,v2]Tv=[v_1,v_2]^Tv=[v1,v2]T。则有:
z=[z1z2]=[w11,w12w21,w22][x1x2]=[w11x1+w12x2w21x1+w22x2](2-6)z=\begin{bmatrix} z_1\\ z_2\\ \end{bmatrix}= \begin{bmatrix} w_{11},w_{12}\\ w_{21},w_{22}\\ \end{bmatrix}\begin{bmatrix} x_1\\ x_2\\ \end{bmatrix}= \begin{bmatrix} w_{11}x_1+w_{12}x_2\\ w_{21}x_1+w_{22}x_2\\ \end{bmatrix}\tag{2-6} z=[z1z2]=[w11,w12w21,w22][x1x2]=[w11x1+w12x2w21x1+w22x2](2-6)
s=[s1s2]=[u11,u12u21,u22][z1z2]=[u11(w11x1+w12x2)+u12(w21x1+w22x2)u21(w11x1+w12x2)+u22(w21x1+w22x2)](2-7)\begin{aligned} s&=\begin{bmatrix} s_1\\ s_2\\ \end{bmatrix}= \begin{bmatrix} u_{11},u_{12}\\ u_{21},u_{22}\\ \end{bmatrix}\begin{bmatrix} z_1\\ z_2\\ \end{bmatrix}\\ &= \begin{bmatrix} u_{11}(w_{11}x_1+w_{12}x_2)+u_{12}(w_{21}x_1+w_{22}x_2)\\ u_{21}(w_{11}x_1+w_{12}x_2)+u_{22}(w_{21}x_1+w_{22}x_2)\\ \end{bmatrix}\tag{2-7} \end{aligned} s=[s1s2]=[u11,u12u21,u22][z1z2]=[u11(w11x1+w12x2)+u12(w21x1+w22x2)u21(w11x1+w12x2)+u22(w21x1+w22x2)](2-7)
y=[v1,v2][s1s2]=(v1u11x1+v2u21x1)w11+(v1u11x2+v2u21x2)w12+(v1u12x1+v2u22x1)w21+(v1u12x2+v2u22x2)w22(2-8)\begin{aligned} y&= [v_1,v_2]\begin{bmatrix} s_1\\ s_2\\ \end{bmatrix}\\ &=(v_1u_{11}x_1+v_2u_{21}x_1)w_{11}\\ &+(v_1u_{11}x_2+v_2u_{21}x_2)w_{12}\\ &+(v_1u_{12}x_1+v_2u_{22}x_1)w_{21}\\ &+(v_1u_{12}x_2+v_2u_{22}x_2)w_{22} \end{aligned}\tag{2-8} y=[v1,v2][s1s2]=(v1u11x1+v2u21x1)w11+(v1u11x2+v2u21x2)w12+(v1u12x1+v2u22x1)w21+(v1u12x2+v2u22x2)w22(2-8)
损失函数为L=(y−y^)2/2L=(y-\hat y)^2/2L=(y−y^)2/2
则损失函数关于权重参数w1w_1w1的导数为:
dLdw1=(y−y^)dydx=(y−y^)dsTdxdyds=(y−y^)dzTdxdsTdzdyds=(y−y^)[x1,0x2,0][u11,u21u12,u22][v1v2]=(y−y^)[v1x1u11+v2x1u21v1x2u11+v2x2u21](2-9)\begin{aligned} \frac{dL}{dw_1}&=(y-\hat y)\frac{dy}{dx}\\ &=(y-\hat y)\frac{ds^T}{dx}\frac{dy}{ds}\\ &=(y-\hat y)\frac{dz^T}{dx}\frac{ds^T}{dz}\frac{dy}{ds}\\ &=(y-\hat y)\begin{bmatrix} x_1,0\\ x_2,0\\ \end{bmatrix} \begin{bmatrix} u_{11},u_{21}\\ u_{12},u_{22}\\ \end{bmatrix} \begin{bmatrix} v_1\\ v_2 \end{bmatrix}\\ &=(y-\hat y)\begin{bmatrix} v_1x_1u_{11}+v_2x_1u_{21}\\ v_1x_2u_{11}+v_2x_2u_{21} \end{bmatrix}\\ \end{aligned}\tag{2-9} dw1dL=(y−y^)dxdy=(y−y^)dxdsTdsdy=(y−y^)dxdzTdzdsTdsdy=(y−y^)[x1,0x2,0][u11,u21u12,u22][v1v2]=(y−y^)[v1x1u11+v2x1u21v1x2u11+v2x2u21](2-9)
可以验证(2−9)(2-9)(2−9)和前面(2−8)(2-8)(2−8)中直接求得的导数值是一样的。
这里发现了一个小彩蛋:
假设在pytorch的底层实现中,如果从左往右计算,则需要进行进行大量的矩阵乘法。如果有n个2×22\times 22×2的方阵相乘,那么需要进行4×(n−1)4\times (n-1)4×(n−1)次内积。如果从又往左计算,只需要进行2×n2\times n2×n次内积。
pytorch教程之自动求导机制(AUTOGRAD)-从梯度和Jacobian矩阵讲起相关推荐
- Pytorch教程入门系列4----Autograd自动求导机制
系列文章目录 文章目录 系列文章目录 前言 一.Autograd是什么? 二.Autograd的使用方法 1.在tensor中指定 2.重要属性 三.Autograd的进阶知识 1.动态计算图 2.梯 ...
- 【PyTorch基础教程2】自动求导机制(学不会来打我啊)
文章目录 第一部分:深度学习和机器学习 一.机器学习任务 二.ML和DL区别 (1)数据加载 (2)模型实现 (3)训练过程 第二部分:Pytorch部分 一.学习资源 二.自动求导机制 2.1 to ...
- Pytorch Autograd (自动求导机制)
Introduce Pytorch Autograd库 (自动求导机制) 是训练神经网络时,反向误差传播(BP)算法的核心. 本文通过logistic回归模型来介绍Pytorch的自动求导机制.首先, ...
- PyTorch 笔记Ⅱ——PyTorch 自动求导机制
文章目录 Autograd: 自动求导机制 张量(Tensor) 梯度 使用PyTorch计算梯度数值 Autograd 简单的自动求导 复杂的自动求导 Autograd 过程解析 扩展Autogra ...
- PyTorch的计算图和自动求导机制
文章目录 PyTorch的计算图和自动求导机制 自动求导机制简介 自动求导机制实例 梯度函数的使用 计算图构建的启用和禁用 总结 PyTorch的计算图和自动求导机制 自动求导机制简介 PyTorch ...
- Pytorch学习(一)—— 自动求导机制
现在对 CNN 有了一定的了解,同时在 GitHub 上找了几个 examples 来学习,对网络的搭建有了笼统地认识,但是发现有好多基础 pytorch 的知识需要补习,所以慢慢从官网 API 进行 ...
- 【PyTorch学习(三)】Aurograd自动求导机制总结
Aurograd自动求导机制总结 PyTorch中,所有神经网络的核心是 autograd 包.autograd 包为tensor上的所有操作提供了自动求导机制.它是一个在运行时定义(define- ...
- PyTorch定义新的自动求导(Autograd) 函数
PyTorch定义新的自动求导(Autograd) 函数 pytorch官网提供了定义新的求导函数的方法(链接放在文章末尾了),官网举的例子,可能我比较笨,愣是反应了好一会儿才理解.这篇博客主要讲 P ...
- 深度学习修炼(三)——自动求导机制
文章目录 致谢 3 自动求导机制 3.1 传播机制与计算图 3.1.1 前向传播 3.1.2 反向传播 3.2 自动求导 3.3 再来做一次 3.4 线性回归 3.4.1 回归 3.4.2 线性回归的 ...
最新文章
- jquery学习——选择器
- 【CV】给AI一张高清照片,分分钟还你细节满满的3D人体模型,GitHub标星4.4k | 在线可玩...
- pytorch微调bert_香侬读 | RoBERT: 没错,我就是能更强——更大数据规模和仔细调参下的最优BERT
- 根据时间格式字符串取出时分秒各自的数值
- 什么是Gut–Skin Axis
- javascript一次性更换访问统计代码
- Python笔记-U2解锁手机九宫格
- 刚写完的商城erp + 这个商城前台,新鲜出炉。自己1个人写, 包括php框架和前端html页面....
- 记录windows游戏编程——1
- 用摄动法证明fibs的一个公式(变形)
- for(atuo x : s)
- windbg调试命令9(dt、d)
- 大师典藏!齐白石-巨匠笔下的小动物系列数字藏品限量发售!
- 移动硬盘文件夹不见了怎么办?
- Ubuntu18.04网络连接图标上显示问号
- Scaled-YOLOv4: Scaling Cross Stage Partial Network 论文翻译
- 南加大的计算机科学与工程,2019上海软科世界一流学科排名计算机科学与工程专业排名南加州大学排名第15...
- 针对英夫利昔单抗或阿达木单抗的抗体存在与否决定转用依那西普的疗效
- 902绿幽灵802绿钻(绿精灵)全部冠号
- 3500字长文讲透《CRM商机管理是什么》
热门文章
- DSPE-PEG-N3,磷脂-聚乙二醇-叠氮 点击化学PEG试剂,可用于药物传递、基因转染和生物分子修饰
- 关于使用rap2接口模拟数据
- 营收恢复加速增长,盐津铺子上演自我升级“好戏”
- Nature | 数据有限也能预测药物靶点,开源模型Geneformer显著改善基因网络校正疗法...
- 面对员工工作懒散,如何进行有效的改善?
- 计算机毕业设计ssm+vue基本微信小程序的电影票务系统-电影票预订系统
- Fixturlaser对中仪维修GO/NXA Pro/ECO/EVO系列
- EVO安装与问题解决
- 408考研计算机之计算机组成与设计——计算机层次系统概述1
- cookies和缓存的区别_Cookies和缓存之间的区别