导数偏导数的数学定义

参考资料1和2中对导数偏导数的定义都非常明确.导数和偏导数都是函数对自变量而言.从数学定义上讲,求导或者求偏导只有函数对自变量,其余任何情况都是错的.但是很多机器学习的资料和开源库都涉及到标量对向量求导.比如下面这个pytorch的例子.

import torch
x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)
y = x ** 2 + 2
z = torch.sum(y)
z.backward()
print(x.grad)

简单解释下,设\(x=[x_1,x_2,x_3]\),则

\[\begin{equation*}
z=x_1^2+x_2^2+x_3^2+6
\end{equation*}
\]

\[\begin{equation*}
\frac{\partial z}{\partial x_1}=2x_1
\end{equation*}
\]

\[\begin{equation*}
\frac{\partial z}{\partial x_2}=2x_2
\end{equation*}
\]

\[\begin{equation*}
\frac{\partial z}{\partial x_3}=2x_3
\end{equation*}
\]

将\(x_1=1.0\),\(x_2=2.0\),\(x_3=3.0\)代入就可以得到

\[\begin{equation*}
(\frac{\partial z}{\partial x_1},\frac{\partial z}{\partial x_2},\frac{\partial z}{\partial x_3})=(2x_1,2x_2,2x_3)=(2.0,4.0,6.0)
\end{equation*}
\]

结果是和pytorch的输出是一样的.反过来想想,其实所谓的"标量对向量求导"本质上是函数对各个自变量求导,这里只是把各个自变量看成一个向量.和数学上的定义并不矛盾.

backward的gradient参数作用

现在有如下问题,已知

\[\begin{equation*}
y_1=x_1x_2x_3
\end{equation*}
\]

\[\begin{equation*}
y_2=x_1+x_2+x_3
\end{equation*}
\]

\[\begin{equation*}
y_3=x_1+x_2x_3
\end{equation*}
\]

\[\begin{equation*}
A=f(y_1,y_2,y_3)
\end{equation*}
\]

其中函数\(f(y_1,y_2,y_3)\)的具体定义未知,现在求

\[\begin{equation*}
\frac{\partial A}{\partial x_1}=?
\end{equation*}
\]

\[\begin{equation*}
\frac{\partial A}{\partial x_2}=?
\end{equation*}
\]

\[\begin{equation*}
\frac{\partial A}{\partial x_3}=?
\end{equation*}
\]

根据参考资料2中讲的多元复合函数的求导法则.

\[\begin{equation*}
\frac{\partial A}{\partial x_1}=\frac{\partial A}{\partial y_1}\frac{\partial y_1}{\partial x_1}+\frac{\partial A}{\partial y_2}\frac{\partial y_2}{\partial x_1}+\frac{\partial A}{\partial y_3}\frac{\partial y_3}{\partial x_1}
\end{equation*}
\]

\[\begin{equation*}
\frac{\partial A}{\partial x_2}=\frac{\partial A}{\partial y_1}\frac{\partial y_1}{\partial x_2}+\frac{\partial A}{\partial y_2}\frac{\partial y_2}{\partial x_2}+\frac{\partial A}{\partial y_3}\frac{\partial y_3}{\partial x_2}
\end{equation*}
\]

\[\begin{equation*}
\frac{\partial A}{\partial x_3}=\frac{\partial A}{\partial y_1}\frac{\partial y_1}{\partial x_3}+\frac{\partial A}{\partial y_2}\frac{\partial y_2}{\partial x_3}+\frac{\partial A}{\partial y_3}\frac{\partial y_3}{\partial x_3}
\end{equation*}
\]

上面3个等式可以写成矩阵相乘的形式.如下

\[\begin{equation}\label{simple}
[\frac{\partial A}{\partial x_1},\frac{\partial A}{\partial x_2},\frac{\partial A}{\partial x_3}]=
[\frac{\partial A}{\partial y_1},\frac{\partial A}{\partial y_2},\frac{\partial A}{\partial y_3}]
\left[
\begin{matrix}
\frac{\partial y_1}{\partial x_1} & \frac{\partial y_1}{\partial x_2} & \frac{\partial A}{\partial x_3} \\
\frac{\partial y_2}{\partial x_1} & \frac{\partial y_2}{\partial x_2} & \frac{\partial A}{\partial x_3} \\
\frac{\partial y_3}{\partial x_1} & \frac{\partial y_3}{\partial x_2} & \frac{\partial A}{\partial x_3}
\end{matrix}
\right]
\end{equation}
\]

其中

\[\begin{equation*}
\left[
\begin{matrix}
\frac{\partial y_1}{\partial x_1} & \frac{\partial y_1}{\partial x_2} & \frac{\partial y_1}{\partial x_3} \\
\frac{\partial y_2}{\partial x_1} & \frac{\partial y_2}{\partial x_2} & \frac{\partial y_2}{\partial x_3} \\
\frac{\partial y_3}{\partial x_1} & \frac{\partial y_3}{\partial x_2} & \frac{\partial y_3}{\partial x_3}
\end{matrix}
\right]
\end{equation*}
\]

叫作雅可比(Jacobian)式.雅可比式可以根据已知条件求出.现在只要知道\([\frac{\partial A}{\partial y_1},\frac{\partial A}{\partial y_2},\frac{\partial A}{\partial y_3}]\)的值,哪怕不知道\(f(y_1,y_2,y_3)\)的具体形式也能求出来\([\frac{\partial A}{\partial x_1},\frac{\partial A}{\partial x_2},\frac{\partial A}{\partial x_3}]\). 那现在的现在的问题是:

怎么样才能求出

\[\begin{equation*}
[\frac{\partial A}{\partial y_1},\frac{\partial A}{\partial y_2},\frac{\partial A}{\partial y_3}]
\end{equation*}
\]

答案是由pytorch的backward函数的gradient参数提供.这就是gradient参数的作用. 参数gradient能解决什么问题,有什么实际的作用呢?说实话,因为我才接触到pytorch,还真没有见过现实中怎么用gradient参数.但是目前可以通过数学意义来理解,就是可以忽略复合函数某个位置之前的所有函数 的具体形式,直接给定一个梯度来求得对各个自变量的偏导.

上面各个方程用代码表示如下所示:

# coding utf-8
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 * x2 * x3
y[1] = x1 + x2 + x3
y[2] = x1 + x2 * x3
x = torch.tensor([x1, x2, x3])
y.backward(torch.tensor([0.1, 0.2, 0.3], dtype=torch.float))
print(x1.grad)
print(x2.grad)
print(x3.grad)

按照上用的推导方法

\[\begin{equation*}
\begin{split}
[\frac{\partial A}{\partial x_1},\frac{\partial A}{\partial x_2},\frac{\partial A}{\partial x_3}]
&=[\frac{\partial A}{\partial y_1},\frac{\partial A}{\partial y_2},\frac{\partial A}{\partial y_3}]
\left[
\begin{matrix}
x_2x_3 & x_1x_3 & x_1x_2 \\
1 & 1 & 1 \\
1 & x_3 & x_2
\end{matrix}
\right]
&=[0.1,0.2,0.3]
\left[
\begin{matrix}
6 & 3 & 2 \\
1 & 1 & 1 \\
1 & 3 & 2
\end{matrix}
\right]
&=[1.1,1.4,1.0]
\end{split}
\end{equation*}
\]

和代码的运行结果是一样的.

参考资料

  1. 同济大学数学系,高等数学第七版上册,高等教育出版社,p75-76, 2015.
  2. 同济大学数学系,高等数学第七版下册,高等教育出版社,p78-80,p88-91, 2015.
  3. Calculus,Thirteenth Edition,p822, 2013.
  4. 详解Pytorch 自动微分里的(vector-Jacobian product)
  5. PyTorch 的 backward 为什么有一个 grad_variables 参数?)

ARTS-S pytorch中backward函数的gradient参数作用的更多相关文章

  1. pytorch autograd backward函数中 retain_graph参数的作用,简单例子分析,以及create_graph参数的作用

    retain_graph参数的作用 官方定义: retain_graph (bool, optional) – If False, the graph used to compute the grad ...

  2. JavaScript中的函数-7---函数的作用,定义,调用

    JavaScript中的函数 函数也是对象,并且是javascript中的一等公民,可以用来创建普通对象.对象只是属性和值的集合 学习目标 1.掌握函数的作用 2.掌握函数的定义 3.掌握函数的调用 ...

  3. ARTS-S pytorch中Conv2d函数padding和stride含义

    padding是输入数据最边缘补0的个数,默认是0,即不补0. stride是进行一次卷积后,特征图滑动几格,默认是1,即滑动一格.

  4. Pytorch中pad函数toch.nn.functional.pad()的用法

    padding操作是给图像外围加像素点. 为了实际说明操作过程,这里我们使用一张实际的图片来做一下处理. 这张图片是大小是(256,256),使用pad来给它加上一个黑色的边框.具体代码如下: 1 2 ...

  5. JavaScript中匿名函数循环传参数(不触发函数的执行)

    我们都知道定义函数的方式有两种,一种是函数声明,另一种是函数表达式,函数声明的语法是这样的: function functionName(arg0, arg1, arg2) { // 函数体 } 函数 ...

  6. 控制台应用程序中Main函数的args参数

    在VS中添加参数 菜单   项目   --   你的项目属性   --   调试   --   启动选项   --   命令行参数 参数之间用空格分隔开就可以了,如果参数有空格,以双引号风格

  7. python中调用函数时,参数顺序与参数赋值问题

    设置类和函数如下:class MM(): def ff(self,url(1),method(2),data=None(3),cookie=None(4)): if method.lower()==& ...

  8. 交叉熵的数学原理及应用——pytorch中的CrossEntropyLoss()函数

    分类问题中,交叉熵函数是比较常用也是比较基础的损失函数,原来就是了解,但一直搞不懂他是怎么来的?为什么交叉熵能够表征真实样本标签和预测概率之间的差值?趁着这次学习把这些概念系统学习了一下. 首先说起交 ...

  9. PyTorch中的C++扩展

    今天要聊聊用 PyTorch 进行 C++ 扩展. 在正式开始前,我们需要了解 PyTorch 如何自定义module.这其中,最常见的就是在 python 中继承torch.nn.Module,用 ...

随机推荐

  1. 别翻了,这篇文章绝对让你深刻理解java类的加载以及ClassLoader源码分析【JVM篇二】

    目录 1.什么是类的加载(类初始化) 2.类的生命周期 3.接口的加载过程 4.解开开篇的面试题 5.理解首次主动使用 6.类加载器 7.关于命名空间 8.JVM类加载机制 9.双亲委派模型 10.C ...

  2. Linux入门之安装及相关知识。

    一.VMware虚拟机安装与使用 1.1.VMware 简介 VMware是一个虚拟PC的软件,可以在现有的操 作系统上虚拟出一个新的硬件环境,相当于模拟 出一台新的PC.以此来实现在一台机器上真正 ...

  3. windows 通过appache链接cgi程序

    #!D:\Python27\ print 'Content-type: text/plain' print print 'Hello, world' 出现错误 The server encounter ...

  4. 小白学习React官方文档看不懂怎么办?

    最近在上React课程的时候,发现好多同学不会看文档,所以在这里写一篇文章,希望能给同学们一点点启发. 我们首先打开React官方网站——https://react.docschina.org/doc ...

  5. python_08

    一.作业 ''' 主页: 图标地址.下载次数.大小.详情页地址 详情页: 游戏名.好评率.评论数.小编点评.下载地址.简介.网友评论.1-5张截图链接地址. https://www.wandoujia ...

  6. GeoServer CQL查询时中文问题

    1.GeoServer可以进行CQL与ECQL过滤,wms和wfs都可以 2.CQL与ECQL查询时,当传中文时会报错.将中文转为Unicode编码后就可以 /* *js Unicode编码转换 */ ...

  7. Java从零开始(前篇)

    前篇 自述 本人大三通信专业,咸鱼一枚,对专业所学傅里叶变换等实在提不起兴趣. 幸好略学过c系列语言,但也浅尝辄止,浑浑噩噩,深入之后被指针弄地晕头转向. 想在毕业后转行计算机,于是我下定决心从零开始 ...

  8. Python 中国大学排名定向爬虫

    代码来自于中国大学Mooc北京理工大学Pythont教学团队:https://www.icourse163.org/learn/BIT-1001870001#/learn/content?type=d ...

  9. NTP服务编译安装报错:/usr/bin/ld: cannot find –lcap

    [root@localhost local]# find / -name "*libcap.so*" [root@localhost ntp-4.2.8p13]# cd /usr/ ...

  10. 简单聊一聊spring cloud stream和kafka的那点事

    Spring Cloud Stream is a framework for building highly scalable event-driven microservices connected ...