导数偏导数的数学定义

参考资料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. leetcode算法笔记:二叉树,动态规划和回溯法

    在二叉树中增加一行 题目描述 给定一个二叉树,根节点为第1层,深度为 1.在其第 d 层追加一行值为 v 的节点. 添加规则:给定一个深度值 d (正整数),针对深度为 d-1 层的每一非空节点 N, ...

  2. nyoj 53-不高兴的小明 (遍历)

    53-不高兴的小明 内存限制:64MB 时间限制:3000ms Special Judge: No accepted:28 submit:89 题目描述:    小明又出问题了.妈妈认为聪明的小明应该 ...

  3. 关键路径法(Critical Path Method, CPM)

    1.活动节点描述及计算公式 通过分析项目过程中哪个活动序列进度安排的总时差最少来预测项目工期的网络分析. 产生目的:为了解决,在庞大而复杂的项目中,如何合理而有效地组织人力.物力和财力,使之在有限资源 ...

  4. 你必须知道的容器日志 (2) 开源日志管理方案 ELK

    本篇已加入<.NET Core on K8S学习实践系列文章索引>,可以点击查看更多容器化技术相关系列文章.上一篇<你必须知道的容器日志(1)>中介绍了Docker自带的log ...

  5. 移动端vue页面禁止移动/滚动

    当需要在移动端中禁止页面滚动,加入:@touchmove.prevent即可,例子如下 <template> <div @touchmove.prevent> <h3 c ...

  6. Android 8.1 自定义热点的时候设置了热点maxLength="32",但是在希伯来语等状态下还是发现在没到32个字符之前就无法把热点设置成功了

    初步认为应该是与热点名称的字节数有关. 然后开始查看源码. /Settings/res/xml/tether_prefs.xml 中的 <Preference android:key=" ...

  7. 20191107-3 beta week 2/2 Scrum立会报告+燃尽图 02

    此作业要求参见[https://edu.cnblogs.com/campus/nenu/2019fall/homework/9955] 一.小组情况 队名:扛把子 组长:孙晓宇 组员:宋晓丽 梁梦瑶 ...

  8. webapi跨域使用session

    在之前的项目中,我们设置跨域都是直接在web.config中设置的. 这样是可以实现跨域访问的.因为我们这边一般情况下一个webapi会有多个网站.小程序.微信公众号等访问,所以这样设置是没有问题的. ...

  9. 《手把手教你》系列练习篇之2-python+ selenium自动化测试(详细教程)

    1. 简介 今天我们还是继续练习练习基本功,各位小伙伴要耐住住性子,要耐得住寂寞啊,不要急躁,后面你会感谢你在前边的不断练习的.到后面也是检验你前边的学习成果的一次很好实践. 本文介绍如何通过link ...

  10. 从零开始手写 spring ioc 框架,深入学习 spring 源码

    IoC Ioc 是一款 spring ioc 核心功能简化实现版本,便于学习和理解原理. 创作目的 使用 spring 很长时间,对于 spring 使用非常频繁,实际上对于源码一直没有静下心来学习过 ...